import { createSignal, For, Show } from "solid-js";
import type { PeerInfo } from "@psx/shared";
import { ApiError, type ApiClient, type Lobby } from "../net/ApiClient.js";
import { NetSession } from "../net/NetSession.js";
import { RemotePlayers } from "../net/RemotePlayers.js";

export interface LobbyScreenProps {
  api: ApiClient;
  /** Builds the session once a lobby is joined; returns the live NetSession. */
  onConnect(lobbyCode: string): Promise<NetSession>;
  onClose(): void;
}

type Stage = "auth" | "menu" | "lobby";

/** Co-op lobby — GDD §8, §9. */
export function LobbyScreen(props: LobbyScreenProps) {
  const [stage, setStage] = createSignal<Stage>(props.api.isAuthenticated ? "menu" : "auth");
  const [busy, setBusy] = createSignal(false);
  const [error, setError] = createSignal<string | null>(null);

  const [username, setUsername] = createSignal("");
  const [password, setPassword] = createSignal("");
  const [isRegistering, setIsRegistering] = createSignal(false);
  const [joinCode, setJoinCode] = createSignal("");

  const [lobby, setLobby] = createSignal<Lobby | null>(null);
  const [peers, setPeers] = createSignal<PeerInfo[]>([]);
  const [session, setSession] = createSignal<NetSession | null>(null);

  /** Wraps an async action with the shared busy/error handling. */
  const run = async (action: () => Promise<void>) => {
    setBusy(true);
    setError(null);
    try {
      await action();
    } catch (cause) {
      setError(cause instanceof ApiError ? cause.message : String(cause));
    } finally {
      setBusy(false);
    }
  };

  const authenticate = () =>
    run(async () => {
      if (isRegistering()) {
        await props.api.register(username(), `${username()}@local.test`, password());
      } else {
        await props.api.login(username(), password());
      }
      setStage("menu");
    });

  const enterLobby = async (joined: Lobby) => {
    setLobby(joined);
    const net = await props.onConnect(joined.code);
    net.onPeersChanged = (list) => setPeers(list);
    setPeers(net.peerList());
    setSession(net);
    setStage("lobby");
  };

  const hostGame = () => run(async () => enterLobby(await props.api.createLobby()));

  const joinGame = () =>
    run(async () => enterLobby(await props.api.joinLobby(joinCode().trim().toUpperCase())));

  const toggleReady = () => {
    const me = peers().find((peer) => peer.peerId === session()?.localPeerId);
    session()?.setReady(!(me?.isReady ?? false));
  };

  const isHost = () => session()?.isHost ?? false;

  return (
    <div class="panel panel--lobby">
      <header class="panel__header">
        <h2>Co-op</h2>
        <button type="button" class="panel__close" onClick={() => props.onClose()}>
          ESC
        </button>
      </header>

      <Show when={error()}>{(message) => <p class="lobby__error">{message()}</p>}</Show>

      <Show when={stage() === "auth"}>
        <form
          class="lobby__form"
          onSubmit={(event) => {
            event.preventDefault();
            void authenticate();
          }}
        >
          <label>
            Username
            <input
              type="text"
              value={username()}
              autocomplete="username"
              onInput={(event) => setUsername(event.currentTarget.value)}
            />
          </label>
          <label>
            Password
            <input
              type="password"
              value={password()}
              autocomplete="current-password"
              onInput={(event) => setPassword(event.currentTarget.value)}
            />
          </label>
          <div class="lobby__actions">
            <button type="submit" disabled={busy()}>
              {isRegistering() ? "Create account" : "Sign in"}
            </button>
            <button type="button" class="lobby__link" onClick={() => setIsRegistering((v) => !v)}>
              {isRegistering() ? "I already have an account" : "Create one instead"}
            </button>
          </div>
        </form>
      </Show>

      <Show when={stage() === "menu"}>
        <div class="lobby__menu">
          <button type="button" disabled={busy()} onClick={() => void hostGame()}>
            Host a session
          </button>

          <div class="lobby__join">
            <input
              type="text"
              placeholder="CODE"
              maxlength="5"
              value={joinCode()}
              onInput={(event) => setJoinCode(event.currentTarget.value.toUpperCase())}
            />
            <button type="button" disabled={busy() || joinCode().length < 4} onClick={() => void joinGame()}>
              Join
            </button>
          </div>
        </div>
      </Show>

      <Show when={stage() === "lobby"}>
        <div class="lobby__room">
          <p class="lobby__code">
            Room code <strong>{lobby()?.code}</strong>
          </p>

          <ul class="lobby__players">
            <For each={peers()} fallback={<li class="lobby__waiting">Waiting for players…</li>}>
              {(peer) => (
                <li>
                  <span
                    class="lobby__swatch"
                    style={{ background: RemotePlayers.cssColorFor(peer.peerId) }}
                  />
                  <span class="lobby__name">{peer.displayName}</span>
                  <Show when={peer.isHost}>
                    <span class="lobby__tag">HOST</span>
                  </Show>
                  <span classList={{ lobby__ready: true, "lobby__ready--on": peer.isReady }}>
                    {peer.isReady ? "READY" : "…"}
                  </span>
                </li>
              )}
            </For>
          </ul>

          <div class="lobby__actions">
            <button type="button" onClick={toggleReady}>
              Toggle ready
            </button>
            <Show when={isHost()}>
              <button type="button" onClick={() => props.onClose()}>
                Begin
              </button>
            </Show>
          </div>

          <p class="lobby__hint">
            Everyone spawns into the room already running behind this menu. Close it to play.
          </p>
        </div>
      </Show>
    </div>
  );
}
