const app = document.getElementById("app");
const state = {
  token: localStorage.getItem("catan_token"),
  username: localStorage.getItem("catan_user"),
  lobby: [],
  models: [],
  stats: null,
  currentGame: null,
  gameState: null,
  ws: null,
};

const resourceColors = {
  brick: "#c46a44",
  lumber: "#4a6d4a",
  wool: "#8cc071",
  grain: "#e2c065",
  ore: "#7a7c83",
  desert: "#d8c18f",
};

function api(path, options = {}) {
  const headers = options.headers || {};
  if (state.token) {
    headers.Authorization = `Bearer ${state.token}`;
  }
  return fetch(path, { ...options, headers }).then(async (resp) => {
    const data = await resp.json().catch(() => ({}));
    if (!resp.ok) {
      throw new Error(data.detail || "Request failed");
    }
    return data;
  });
}

function setAuth(token, username) {
  state.token = token;
  state.username = username;
  localStorage.setItem("catan_token", token);
  localStorage.setItem("catan_user", username);
}

function clearAuth() {
  state.token = null;
  state.username = null;
  localStorage.removeItem("catan_token");
  localStorage.removeItem("catan_user");
}

function showToast(message) {
  alert(message);
}

function renderHeader() {
  return `
    <div class="header">
      <div class="logo">CATAN ARENA</div>
      <div style="display:flex; gap:12px; align-items:center;">
        <span class="small">${state.username || "Guest"}</span>
        ${state.token ? `<button class="button ghost" id="logout-btn">Logout</button>` : ""}
      </div>
    </div>
  `;
}

function renderLogin() {
  app.innerHTML = `
    ${renderHeader()}
    <div class="container">
      <div class="grid two">
        <div class="card">
          <div class="section-title">Login</div>
          <div class="panel-stack">
            <input class="input" id="login-user" placeholder="Username" />
            <input class="input" id="login-pass" type="password" placeholder="Password" />
            <button class="button" id="login-btn">Enter Arena</button>
          </div>
        </div>
        <div class="card">
          <div class="section-title">Create Account</div>
          <div class="panel-stack">
            <input class="input" id="register-user" placeholder="Username" />
            <input class="input" id="register-pass" type="password" placeholder="Password" />
            <button class="button secondary" id="register-btn">Register</button>
          </div>
        </div>
      </div>
    </div>
  `;

  document.getElementById("login-btn").addEventListener("click", async () => {
    try {
      const username = document.getElementById("login-user").value.trim();
      const password = document.getElementById("login-pass").value.trim();
      const data = await api("/api/login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ username, password }),
      });
      setAuth(data.token, data.username);
      await loadLobby();
    } catch (err) {
      showToast(err.message);
    }
  });

  document.getElementById("register-btn").addEventListener("click", async () => {
    try {
      const username = document.getElementById("register-user").value.trim();
      const password = document.getElementById("register-pass").value.trim();
      const data = await api("/api/register", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ username, password }),
      });
      setAuth(data.token, data.username);
      await loadLobby();
    } catch (err) {
      showToast(err.message);
    }
  });
}

async function loadLobby() {
  try {
    const [lobby, models, stats] = await Promise.all([
      api("/api/lobby"),
      api("/api/models"),
      api("/api/stats"),
    ]);
    state.lobby = lobby.games || [];
    state.models = models.models || [];
    state.stats = stats;
    renderLobby();
  } catch (err) {
    clearAuth();
    renderLogin();
  }
}

function lobbyGameCard(game) {
  const players = game.players
    .map((slot) => slot.name || "Open")
    .map((name) => `<span class="player-tag">${name}</span>`)
    .join("");
  return `
    <div class="lobby-card">
      <div style="display:flex; justify-content:space-between; align-items:center;">
        <strong>${game.name}</strong>
        <span class="badge">${game.status}</span>
      </div>
      <div style="display:flex; flex-wrap:wrap; gap:6px;">${players}</div>
      <div style="display:flex; gap:8px; flex-wrap:wrap;">
        <button class="button" data-action="join" data-id="${game.id}">Join</button>
        <button class="button ghost" data-action="ai" data-id="${game.id}">Add AI</button>
        <button class="button secondary" data-action="start" data-id="${game.id}">Start</button>
      </div>
    </div>
  `;
}

function renderLobby() {
  app.innerHTML = `
    ${renderHeader()}
    <div class="container">
      <div class="grid two">
        <div class="card">
          <div class="section-title">Lobby</div>
          <div class="panel-stack">
            ${state.lobby.map(lobbyGameCard).join("") || "<p>No active games yet.</p>"}
          </div>
        </div>
        <div class="panel-stack">
          <div class="card">
            <div class="section-title">Create Game</div>
            <div class="panel-stack">
              <input class="input" id="game-name" placeholder="Game name" />
              <select class="input" id="game-size">
                <option value="3">3 players</option>
                <option value="4" selected>4 players</option>
              </select>
              <button class="button" id="create-game">Create</button>
            </div>
          </div>
          <div class="card">
            <div class="section-title">Your Stats</div>
            <div class="panel-stack">
              <div>Total games: ${state.stats?.total_games ?? 0}</div>
              <div>Your games: ${state.stats?.user_games ?? 0}</div>
              <div>Your wins: ${state.stats?.user_wins ?? 0}</div>
              <div>Avg turns: ${(state.stats?.avg_turns ?? 0).toFixed(1)}</div>
            </div>
          </div>
          <div class="card">
            <div class="section-title">AI Models</div>
            <div class="panel-stack">
              ${(state.models || []).map((model) => `<span class="player-tag">${model}</span>`).join("") || "<span class=\"small\">No models uploaded yet.</span>"}
            </div>
          </div>
        </div>
      </div>
    </div>
  `;

  document.getElementById("create-game").addEventListener("click", async () => {
    try {
      const name = document.getElementById("game-name").value.trim() || "Untitled Room";
      const max_players = parseInt(document.getElementById("game-size").value, 10);
      await api("/api/games", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ name, max_players }),
      });
      await loadLobby();
    } catch (err) {
      showToast(err.message);
    }
  });

  document.querySelectorAll("[data-action='join']").forEach((btn) => {
    btn.addEventListener("click", async () => {
      try {
        const id = btn.dataset.id;
        await api(`/api/games/${id}/join`, { method: "POST" });
        openGame(id);
      } catch (err) {
        showToast(err.message);
      }
    });
  });

  document.querySelectorAll("[data-action='ai']").forEach((btn) => {
    btn.addEventListener("click", async () => {
      const id = btn.dataset.id;
      const aiType = prompt("AI type: random or model?") || "random";
      let payload = { ai_type: aiType };
      if (aiType === "model") {
        const model = prompt(`Model name: ${state.models.join(", ")}`);
        payload.model_name = model;
      }
      try {
        await api(`/api/games/${id}/add_ai`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(payload),
        });
        await loadLobby();
      } catch (err) {
        showToast(err.message);
      }
    });
  });

  document.querySelectorAll("[data-action='start']").forEach((btn) => {
    btn.addEventListener("click", async () => {
      try {
        const id = btn.dataset.id;
        await api(`/api/games/${id}/start`, { method: "POST" });
        openGame(id);
      } catch (err) {
        showToast(err.message);
      }
    });
  });

  const logoutBtn = document.getElementById("logout-btn");
  if (logoutBtn) {
    logoutBtn.addEventListener("click", () => {
      clearAuth();
      renderLogin();
    });
  }
}

function openGame(id) {
  state.currentGame = id;
  if (state.ws) {
    state.ws.close();
  }
  const ws = new WebSocket(`${location.protocol === "https:" ? "wss" : "ws"}://${location.host}/ws/games/${id}?token=${state.token}`);
  ws.onmessage = (event) => {
    const msg = JSON.parse(event.data);
    if (msg.type === "state") {
      state.gameState = msg.data;
      renderGame();
    }
  };
  ws.onclose = () => {
    state.ws = null;
  };
  state.ws = ws;
  renderGame();
}

function resourceSummary(resources) {
  if (!resources) return "";
  if (resources.hidden !== undefined) {
    return `Hidden cards: ${resources.hidden}`;
  }
  return Object.entries(resources)
    .map(([k, v]) => `${k}:${v}`)
    .join(" · ");
}

function renderPlayers(game) {
  if (!game) return "";
  return Object.entries(game.players)
    .map(([name, pdata]) => {
      const color = pdata.color || "#333";
      return `
        <div style="display:flex; align-items:center; gap:8px;">
          <span class="player-tag" style="background:${color}; color:white;">${name}</span>
          <span class="small">VP ${pdata.victory_points}</span>
          <span class="small">${resourceSummary(pdata.resources)}</span>
        </div>
      `;
    })
    .join("");
}

function cubeToPixel(coord, scale) {
  const [x, , z] = coord;
  const sqrt3 = Math.sqrt(3);
  return {
    x: scale * (sqrt3 * x + (sqrt3 / 2) * z),
    y: scale * (1.5 * z),
  };
}

function hexCorners(cx, cy, size) {
  const points = [];
  for (let i = 0; i < 6; i++) {
    const angle = (Math.PI / 180) * (60 * i - 30);
    points.push([cx + size * Math.cos(angle), cy + size * Math.sin(angle)]);
  }
  return points;
}

function renderBoard(board, game) {
  if (!board || !game) return "";
  const size = 48;
  const cornerScale = size / 3;
  const hexes = Object.values(board.hexes || {});
  const corners = board.corners || {};
  const edges = Object.values(board.edges || {});

  const hexPositions = hexes.map((hex) => {
    const pos = cubeToPixel(hex.coord, size);
    return { ...hex, pos };
  });

  const cornerPositions = {};
  Object.entries(corners).forEach(([id, corner]) => {
    cornerPositions[id] = {
      ...corner,
      pos: cubeToPixel(corner.coord, cornerScale),
    };
  });

  const allPositions = [
    ...hexPositions.map((h) => h.pos),
    ...Object.values(cornerPositions).map((c) => c.pos),
  ];
  const minX = Math.min(...allPositions.map((p) => p.x));
  const maxX = Math.max(...allPositions.map((p) => p.x));
  const minY = Math.min(...allPositions.map((p) => p.y));
  const maxY = Math.max(...allPositions.map((p) => p.y));
  const padding = 80;
  const viewBox = `${minX - padding} ${minY - padding} ${maxX - minX + padding * 2} ${maxY - minY + padding * 2}`;

  const playerColors = {};
  Object.entries(game.players).forEach(([name, pdata]) => {
    playerColors[name] = pdata.color || "#333";
  });

  const roadLines = edges
    .filter((edge) => edge.owner)
    .map((edge) => {
      const a = cornerPositions[edge.a];
      const b = cornerPositions[edge.b];
      if (!a || !b) return "";
      const color = playerColors[edge.owner] || "#222";
      return `<line x1="${a.pos.x}" y1="${a.pos.y}" x2="${b.pos.x}" y2="${b.pos.y}" stroke="${color}" stroke-width="6" stroke-linecap="round" />`;
    })
    .join("");

  const cornerNodes = Object.entries(cornerPositions)
    .filter(([, corner]) => corner.owner)
    .map(([, corner]) => {
      const radius = corner.building === "city" ? 10 : 7;
      const color = playerColors[corner.owner] || "#222";
      return `<circle cx="${corner.pos.x}" cy="${corner.pos.y}" r="${radius}" fill="${color}" stroke="#fff" stroke-width="2" />`;
    })
    .join("");

  const hexShapes = hexPositions
    .map((hex) => {
      const points = hexCorners(hex.pos.x, hex.pos.y, size - 4)
        .map((pt) => pt.join(","))
        .join(" ");
      const fill = resourceColors[hex.resource] || "#e0c89a";
      const number = hex.number || "";
      const robber = hex.robber ? "<circle r='8' fill='rgba(0,0,0,0.4)' />" : "";
      return `
        <g>
          <polygon points="${points}" fill="${fill}" stroke="rgba(0,0,0,0.2)" stroke-width="2" />
          <text x="${hex.pos.x}" y="${hex.pos.y}" text-anchor="middle" font-size="16" fill="#3a2a1a" font-weight="600">${number}</text>
          <g transform="translate(${hex.pos.x}, ${hex.pos.y + 20})">${robber}</g>
        </g>
      `;
    })
    .join("");

  return `
    <svg class="board-svg" viewBox="${viewBox}">
      ${hexShapes}
      ${roadLines}
      ${cornerNodes}
    </svg>
  `;
}

function actionLabel(action) {
  const payload = action.payload || {};
  switch (action.type) {
    case "place_initial":
      return `Place initial: corner ${payload.corner} / road ${payload.road}`;
    case "build_road":
      return `Build road: edge ${payload.edge}`;
    case "build_settlement":
      return `Build settlement: corner ${payload.corner}`;
    case "build_city":
      return `Build city: corner ${payload.corner}`;
    case "buy_development":
      return "Buy development card";
    case "roll":
      return "Roll dice";
    case "end_turn":
      return "End turn";
    case "trade_bank":
      return `Trade bank: ${payload.give} -> ${payload.receive} (ratio ${payload.ratio})`;
    case "trade_player":
      return `Trade player ${payload.target}: ${JSON.stringify(payload.offer)} for ${JSON.stringify(payload.request)}`;
    case "play_knight":
      return "Play Knight";
    case "move_robber":
      return "Move Robber";
    case "play_road_building":
      return "Play Road Building";
    case "play_year_of_plenty":
      return "Play Year of Plenty";
    case "play_monopoly":
      return "Play Monopoly";
    case "discard":
      return `Discard ${payload.required}`;
    default:
      return `${action.type}`;
  }
}

function renderActionForm(action) {
  const payload = action.payload || {};
  const wrapper = document.createElement("div");
  wrapper.className = "action-controls";
  if (action.type === "move_robber" || action.type === "play_knight") {
    const options = payload.options || [];
    const hexSelect = document.createElement("select");
    hexSelect.className = "input";
    options.forEach((opt) => {
      const option = document.createElement("option");
      option.value = opt.hex;
      option.textContent = `Hex ${opt.hex}`;
      hexSelect.appendChild(option);
    });
    const victimSelect = document.createElement("select");
    victimSelect.className = "input";
    function updateVictims() {
      const selected = options.find((opt) => String(opt.hex) === hexSelect.value);
      victimSelect.innerHTML = "";
      const victims = (selected && selected.victims) || [];
      const noneOpt = document.createElement("option");
      noneOpt.value = "";
      noneOpt.textContent = "No victim";
      victimSelect.appendChild(noneOpt);
      victims.forEach((victim) => {
        const opt = document.createElement("option");
        opt.value = victim;
        opt.textContent = victim;
        victimSelect.appendChild(opt);
      });
    }
    hexSelect.addEventListener("change", updateVictims);
    updateVictims();
    wrapper.appendChild(hexSelect);
    wrapper.appendChild(victimSelect);
    wrapper.dataset.builder = "robber";
    wrapper.dataset.options = JSON.stringify(options);
    wrapper._getPayload = () => {
      const selected = options.find((opt) => String(opt.hex) === hexSelect.value) || { victims: [] };
      const victim = victimSelect.value;
      const result = { hex: parseInt(hexSelect.value, 10) };
      if (victim) {
        result.victim = victim;
      }
      return result;
    };
    return wrapper;
  }

  if (action.type === "play_road_building") {
    const edges = payload.edges || [];
    const info = document.createElement("div");
    info.className = "small";
    info.textContent = "Select up to two edges";
    wrapper.appendChild(info);
    const edgeSelect = document.createElement("select");
    edgeSelect.className = "input";
    edgeSelect.multiple = true;
    edges.forEach((edge) => {
      const opt = document.createElement("option");
      opt.value = edge;
      opt.textContent = `Edge ${edge}`;
      edgeSelect.appendChild(opt);
    });
    wrapper.appendChild(edgeSelect);
    wrapper._getPayload = () => {
      const selected = Array.from(edgeSelect.selectedOptions).map((opt) => parseInt(opt.value, 10));
      return { edges: selected.slice(0, 2) };
    };
    return wrapper;
  }

  if (action.type === "play_year_of_plenty") {
    const bank = payload.bank || {};
    const resources = Object.keys(bank);
    const select1 = document.createElement("select");
    const select2 = document.createElement("select");
    select1.className = "input";
    select2.className = "input";
    resources.forEach((res) => {
      const opt1 = document.createElement("option");
      opt1.value = res;
      opt1.textContent = res;
      const opt2 = opt1.cloneNode(true);
      select1.appendChild(opt1);
      select2.appendChild(opt2);
    });
    wrapper.appendChild(select1);
    wrapper.appendChild(select2);
    wrapper._getPayload = () => ({ resources: [select1.value, select2.value] });
    return wrapper;
  }

  if (action.type === "play_monopoly") {
    const resources = payload.resources || ["brick", "lumber", "wool", "grain", "ore"];
    const select = document.createElement("select");
    select.className = "input";
    resources.forEach((res) => {
      const opt = document.createElement("option");
      opt.value = res;
      opt.textContent = res;
      select.appendChild(opt);
    });
    wrapper.appendChild(select);
    wrapper._getPayload = () => ({ resource: select.value });
    return wrapper;
  }

  if (action.type === "discard") {
    const resources = payload.resources || {};
    const required = payload.required || 0;
    const counts = {};
    wrapper.appendChild(document.createTextNode(`Discard ${required} cards`));
    Object.entries(resources).forEach(([res, count]) => {
      if (res === "desert" || count <= 0) return;
      counts[res] = 0;
      const row = document.createElement("div");
      row.style.display = "flex";
      row.style.alignItems = "center";
      row.style.gap = "8px";
      const label = document.createElement("span");
      label.textContent = `${res} (${count})`;
      const input = document.createElement("input");
      input.type = "number";
      input.min = 0;
      input.max = count;
      input.value = 0;
      input.className = "input";
      input.style.maxWidth = "80px";
      input.addEventListener("change", () => {
        counts[res] = parseInt(input.value, 10) || 0;
      });
      row.appendChild(label);
      row.appendChild(input);
      wrapper.appendChild(row);
    });
    wrapper._getPayload = () => ({ player: state.username, cards: counts });
    return wrapper;
  }

  wrapper._getPayload = () => payload;
  return wrapper;
}

function renderGame() {
  const data = state.gameState;
  if (!data) {
    app.innerHTML = `${renderHeader()}<div class="container">Loading...</div>`;
    return;
  }
  const game = data.game;
  const board = data.board;
  const legalActions = data.legal_actions || [];

  app.innerHTML = `
    ${renderHeader()}
    <div class="container">
      <div class="grid three">
        <div class="panel-stack">
          <div class="card">
            <div class="section-title">Players</div>
            <div class="panel-stack">${renderPlayers(game)}</div>
          </div>
          <div class="card">
            <div class="section-title">Action Console</div>
            <div class="action-list" id="action-list"></div>
          </div>
          <div class="card">
            <div class="section-title">Timeline</div>
            <div class="history">${(data.history || [])
              .slice()
              .reverse()
              .map((entry) => `<div>${entry.player}: ${entry.type}</div>`)
              .join("")}</div>
          </div>
        </div>
        <div class="board-shell">
          ${renderBoard(board, game)}
        </div>
        <div class="panel-stack">
          <div class="card">
            <div class="section-title">Status</div>
            <div class="panel-stack">
              <div>Phase: ${game?.phase || "-"}</div>
              <div>Current: ${game?.current_player || "-"}</div>
              <div>Last roll: ${game?.last_roll || "-"}</div>
              <div>Winner: ${game?.winner || "-"}</div>
            </div>
          </div>
          <div class="card">
            <div class="section-title">Bank</div>
            <div>${game ? Object.entries(game.bank)
              .map(([k, v]) => `${k}: ${v}`)
              .join(" · ") : ""}</div>
          </div>
          <div class="card">
            <div class="section-title">Lobby</div>
            <button class="button ghost" id="back-lobby">Back to Lobby</button>
          </div>
        </div>
      </div>
    </div>
  `;

  const actionList = document.getElementById("action-list");
  if (legalActions.length === 0) {
    actionList.innerHTML = "<div class='small'>Waiting for your turn...</div>";
  } else {
    const select = document.createElement("select");
    select.className = "input";
    legalActions.forEach((action, idx) => {
      const opt = document.createElement("option");
      opt.value = idx;
      opt.textContent = actionLabel(action);
      select.appendChild(opt);
    });
    const formHost = document.createElement("div");
    formHost.className = "action-controls";
    let currentForm = renderActionForm(legalActions[0]);
    formHost.appendChild(currentForm);

    select.addEventListener("change", () => {
      formHost.innerHTML = "";
      currentForm = renderActionForm(legalActions[select.value]);
      formHost.appendChild(currentForm);
    });

    const submit = document.createElement("button");
    submit.className = "button";
    submit.textContent = "Send";
    submit.addEventListener("click", async () => {
      const action = legalActions[select.value];
      const payload = currentForm._getPayload ? currentForm._getPayload() : action.payload;
      try {
        await api(`/api/games/${data.id}/action`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ type: action.type, payload }),
        });
      } catch (err) {
        showToast(err.message);
      }
    });

    actionList.appendChild(select);
    actionList.appendChild(formHost);
    actionList.appendChild(submit);
  }

  document.getElementById("back-lobby").addEventListener("click", async () => {
    if (state.ws) {
      state.ws.close();
      state.ws = null;
    }
    await loadLobby();
  });

  const logoutBtn = document.getElementById("logout-btn");
  if (logoutBtn) {
    logoutBtn.addEventListener("click", () => {
      clearAuth();
      renderLogin();
    });
  }
}

(async function bootstrap() {
  if (state.token) {
    await loadLobby();
  } else {
    renderLogin();
  }
})();
