"use client";

import { useState } from "react";

/**
 * The whole installer, as far as the customer is concerned.
 *
 * Two things happen here and nothing else: a key is checked, and the script
 * it unlocks is pulled down and written into place. Everything after that —
 * database, site name, admin account — belongs to the real wizard, which is
 * sitting in the files this page just fetched. Duplicating those steps here
 * would mean maintaining the same five screens twice and having them drift.
 */

type Line = { text: string; detail?: string; kind: "doing" | "done" | "bad" };

export default function Installer() {
  const [license, setLicense] = useState("");
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [lines, setLines] = useState<Line[]>([]);
  const [percent, setPercent] = useState<number | null>(null);
  const [done, setDone] = useState<string | null>(null);
  const [host, setHost] = useState<"cpanel" | "other">("cpanel");

  const say = (line: Line) => setLines((prev) => [...prev, line]);

  async function go(e: React.FormEvent) {
    e.preventDefault();
    if (busy || !license.trim()) return;

    setBusy(true);
    setError(null);
    setLines([]);
    setPercent(null);

    // Step one: the key.
    const act = await fetch("/api/setup/activate", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ license: license.trim() }),
    }).catch(() => null);

    const actData = await act?.json().catch(() => null);

    if (!act?.ok) {
      setError(actData?.error ?? "That key could not be checked. Try again in a moment.");
      setBusy(false);
      return;
    }

    say({ text: "Licence accepted", detail: actData?.domain, kind: "done" });

    // Step two: the script itself, reported as it happens.
    const res = await fetch("/api/setup/fetch", { method: "POST" }).catch(() => null);

    if (!res?.body) {
      setError("The download could not be started. Check the server can reach the internet.");
      setBusy(false);
      return;
    }

    const reader = res.body.getReader();
    const decoder = new TextDecoder();
    let buffer = "";

    for (;;) {
      const { done: finished, value } = await reader.read();
      if (finished) break;

      buffer += decoder.decode(value, { stream: true });
      const parts = buffer.split("\n");
      buffer = parts.pop() ?? "";

      for (const part of parts) {
        if (!part.trim()) continue;

        let event: {
          step?: string;
          state?: string;
          label?: string;
          detail?: string;
          percent?: number;
          version?: string;
          host?: "cpanel" | "other";
        } | null = null;

        try {
          event = JSON.parse(part);
        } catch {
          continue;
        }
        if (!event) continue;

        if (event.step === "error") {
          setError(event.label ?? "Something went wrong.");
          setPercent(null);
          setBusy(false);
          return;
        }

        if (event.state === "progress") {
          setPercent(event.percent ?? null);
          continue;
        }

        if (event.state === "start") {
          setPercent(null);
          say({ text: event.label ?? "", kind: "doing" });
          continue;
        }

        if (event.step === "finished") {
          setPercent(null);
          if (event.host) setHost(event.host);
          setDone(event.version ?? "");
          continue;
        }

        // A finished step replaces the "doing" line it started.
        setPercent(null);
        setLines((prev) => {
          const next = [...prev];
          for (let i = next.length - 1; i >= 0; i -= 1) {
            if (next[i].kind === "doing") {
              next[i] = { text: event!.label ?? next[i].text, detail: event!.detail, kind: "done" };
              return next;
            }
          }
          return [...next, { text: event!.label ?? "", detail: event!.detail, kind: "done" }];
        });
      }
    }

    setBusy(false);
  }

  return (
    <main className="shell">
      <div className="card">
        <div className="brand">
          <span className="mark" aria-hidden>
            h
          </span>
          <span>Installer</span>
        </div>

        {!done && (
          <>
            <h1>Let&rsquo;s get your script</h1>
            <p className="lede">
              This package is just the installer. Enter the licence key from your order and the
              script downloads itself — no files to upload, nothing to unzip.
            </p>

            <form onSubmit={go}>
              <label htmlFor="license">Licence key</label>
              <input
                id="license"
                value={license}
                onChange={(e) => setLicense(e.target.value)}
                placeholder="e.g. DM-301544SD-24"
                autoComplete="off"
                spellCheck={false}
                disabled={busy}
              />

              <button type="submit" disabled={busy || !license.trim()}>
                {busy ? "Working…" : "Install the script"}
              </button>
            </form>
          </>
        )}

        {done && (
          <>
            <h1>Done — one last step</h1>
            <p className="lede">
              Version {done} is on your server. Restart the app once, then come back here and the
              setup wizard takes over: database, site name, your admin account.
            </p>

            {/*
             * One instruction, not two.
             *
             * The server already knows which kind of host it is running on,
             * so there is no reason to show a customer a command for a setup
             * they do not have and let them guess which half applies.
             */}
            <div className="restart">
              {host === "cpanel" ? (
                <div>
                  <b>Restart it like this</b>
                  <span>
                    Open cPanel → <b>Setup Node.js App</b> → find this site → press{" "}
                    <b>RESTART</b>.
                  </span>
                </div>
              ) : (
                <div>
                  <b>Restart it like this</b>
                  <span>
                    Your site is not on cPanel, so it is started by a process manager on the
                    server. If you (or whoever set the server up) used pm2 — the usual choice on a
                    VPS — connect over SSH and run <code>pm2 restart hifod</code>, using whatever
                    name the app was given. If you used something else, restart it the way you
                    normally would; if you are not sure, ask whoever set the server up — it is a
                    one-line job for them.
                  </span>
                </div>
              )}
            </div>

            <button type="button" onClick={() => window.location.reload()}>
              I&rsquo;ve restarted it — continue
            </button>
            <p className="after">
              If you land back on this page, the restart hasn&rsquo;t finished yet. Wait a few
              seconds and press it again.
            </p>
          </>
        )}

        {error && (
          <p className="bad" role="alert">
            {error}
          </p>
        )}

        {lines.length > 0 && (
          <ul className="log">
            {lines.map((l, i) => (
              <li key={i} className={l.kind}>
                <span className="dot" aria-hidden />
                <span className="what">{l.text}</span>
                {l.detail && <span className="detail">{l.detail}</span>}
              </li>
            ))}
          </ul>
        )}

        {percent !== null && (
          <div className="bar" role="progressbar" aria-valuenow={percent}>
            <span style={{ width: `${percent}%` }} />
          </div>
        )}
      </div>

      <p className="foot">Nothing is written to your server until the key checks out.</p>
    </main>
  );
}
