"use client";

import { useEffect, useState } from "react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { SYSTEM_LIST } from "@/lib/systems";
import type { SystemId } from "@/lib/types";
import { useProfile } from "@/lib/profile/context";
import { addAnalyticsEvent } from "@/lib/profile/db";

export function ContributeForm() {
  const router = useRouter();
  const { account, profile } = useProfile();
  const [file, setFile] = useState<File | null>(null);
  const [title, setTitle] = useState("");
  const [system, setSystem] = useState<SystemId | "">("");
  const [author, setAuthor] = useState("");
  const [description, setDescription] = useState("");
  const [license, setLicense] = useState("");
  const [sourceUrl, setSourceUrl] = useState("");
  const [token, setToken] = useState("");
  const [featured, setFeatured] = useState(false);
  const [ack, setAck] = useState(false);
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState("");
  const [msg, setMsg] = useState("");
  const [requiresToken, setRequiresToken] = useState(false);
  const [uploadsAllowed, setUploadsAllowed] = useState(true);

  useEffect(() => {
    void (async () => {
      try {
        const res = await fetch("/api/contribute");
        const data = (await res.json()) as {
          uploads?: { allowed?: boolean; requiresToken?: boolean };
        };
        if (data.uploads) {
          setRequiresToken(Boolean(data.uploads.requiresToken));
          setUploadsAllowed(data.uploads.allowed !== false);
        }
      } catch {
        /* ignore */
      }
    })();
  }, []);

  async function submit(e: React.FormEvent) {
    e.preventDefault();
    if (!file) {
      setErr("Choose a ROM file.");
      return;
    }
    if (!ack) {
      setErr("Confirm the disclaimer before uploading.");
      return;
    }
    setBusy(true);
    setErr("");
    setMsg("");
    try {
      const form = new FormData();
      form.set("file", file);
      if (title.trim()) form.set("title", title.trim());
      if (system) form.set("system", system);
      if (author.trim()) form.set("author", author.trim());
      if (description.trim()) form.set("description", description.trim());
      if (license.trim()) form.set("license", license.trim());
      if (sourceUrl.trim()) form.set("sourceUrl", sourceUrl.trim());
      if (token.trim()) form.set("token", token.trim());
      if (featured) form.set("featured", "true");

      const res = await fetch("/api/contribute", {
        method: "POST",
        body: form,
        headers: token.trim()
          ? { "x-upload-token": token.trim() }
          : undefined,
      });
      const raw = await res.text();
      let data: {
        ok: boolean;
        error?: string;
        message?: string;
        game?: { slug: string; title: string };
      };
      try {
        data = JSON.parse(raw) as typeof data;
      } catch {
        const hint =
          res.status === 413 || /413|entity too large|Request Entity/i.test(raw)
            ? "File too large for the reverse proxy. Set nginx client_max_body_size 300M; (or Apache LimitRequestBody) and reload."
            : res.status === 502 || res.status === 504
              ? "Proxy could not reach the app (502/504). Is Docker hollowcade running on 127.0.0.1:3000?"
              : `Server returned HTML/non-JSON (HTTP ${res.status}). Often nginx body size, a dead Node process, or uploads blocked without a token.`;
        setErr(hint);
        return;
      }
      if (!res.ok || !data.ok) {
        setErr(data.error || "Upload failed.");
        return;
      }
      setMsg(data.message || "Added to the shared catalog.");
      await addAnalyticsEvent({
        type: "contribute",
        accountId: account?.id,
        profileId: profile?.id,
        gameSlug: data.game?.slug,
        label: file.name,
        at: Date.now(),
      });
      setFile(null);
      setTitle("");
      setDescription("");
      if (data.game?.slug) {
        router.refresh();
        setTimeout(() => {
          router.push(`/games/${data.game!.slug}`);
        }, 600);
      }
    } catch (e) {
      setErr(e instanceof Error ? e.message : "Request failed");
    } finally {
      setBusy(false);
    }
  }

  return (
    <form className="mt-8 space-y-4" onSubmit={(e) => void submit(e)}>
      {!uploadsAllowed && (
        <p className="rounded-sm border border-accent-hot/40 bg-accent-hot/10 px-4 py-3 text-sm text-accent-hot">
          Uploads are disabled on this host. Set{" "}
          <code className="text-foreground">HOLLOWCADE_UPLOAD_TOKEN</code> or{" "}
          <code className="text-foreground">HOLLOWCADE_OPEN_CONTRIBUTE=1</code> in
          the server <code className="text-foreground">.env</code>, then{" "}
          <code className="text-foreground">docker compose up -d</code>.
        </p>
      )}
      {uploadsAllowed && requiresToken && (
        <p className="rounded-sm border border-amber/40 bg-amber/5 px-4 py-3 text-sm text-muted">
          This host requires the upload token below (from{" "}
          <code className="text-foreground">HOLLOWCADE_UPLOAD_TOKEN</code>).
        </p>
      )}

      <div className="rounded-sm border border-amber/40 bg-amber/5 px-4 py-3 text-sm text-muted">
        <p className="font-display text-[0.65rem] tracking-wider text-amber uppercase">
          Disclaimer
        </p>
        <p className="mt-2">
          HollowCade is a browser player. You are responsible for the files you
          upload. The site does not verify redistribution rights. Only add ROMs
          you are allowed to share on this host. See{" "}
          <Link href="/terms" className="text-amber underline-offset-2 hover:underline">
            Terms
          </Link>{" "}
          and{" "}
          <Link href="/dmca" className="text-amber underline-offset-2 hover:underline">
            DMCA
          </Link>
          .
        </p>
        <label className="mt-3 flex items-start gap-2 text-foreground">
          <input
            type="checkbox"
            className="mt-1"
            checked={ack}
            onChange={(e) => setAck(e.target.checked)}
            required
          />
          <span>I understand — add this ROM to the public shared catalog.</span>
        </label>
      </div>

      <label className="block text-sm">
        <span className="settings-label">ROM file</span>
        <input
          type="file"
          className="settings-input"
          accept=".nes,.sfc,.smc,.gb,.gbc,.gba,.md,.gen,.n64,.z64,.v64,.nds,.iso,.cso,.pbp,.sms,.gg,.a26,.vb,.chd,.cue,.bin,.zip"
          onChange={(e) => setFile(e.target.files?.[0] ?? null)}
          required
        />
      </label>

      <label className="block text-sm">
        <span className="settings-label">Title (optional)</span>
        <input
          className="settings-input"
          value={title}
          onChange={(e) => setTitle(e.target.value)}
          placeholder="Defaults from filename"
        />
      </label>

      <label className="block text-sm">
        <span className="settings-label">System (optional if detectable)</span>
        <select
          className="settings-input"
          value={system}
          onChange={(e) => setSystem(e.target.value as SystemId | "")}
        >
          <option value="">Auto-detect from extension</option>
          {SYSTEM_LIST.map((s) => (
            <option key={s.id} value={s.id}>
              {s.shortName} — {s.name}
            </option>
          ))}
        </select>
      </label>

      <label className="block text-sm">
        <span className="settings-label">Author (optional)</span>
        <input
          className="settings-input"
          value={author}
          onChange={(e) => setAuthor(e.target.value)}
        />
      </label>

      <label className="block text-sm">
        <span className="settings-label">Description (optional)</span>
        <textarea
          className="settings-input min-h-[4rem]"
          value={description}
          onChange={(e) => setDescription(e.target.value)}
        />
      </label>

      <label className="block text-sm">
        <span className="settings-label">License / notes (optional)</span>
        <input
          className="settings-input"
          value={license}
          onChange={(e) => setLicense(e.target.value)}
          placeholder="MIT, freeware, personal dump, …"
        />
      </label>

      <label className="block text-sm">
        <span className="settings-label">Source URL (optional)</span>
        <input
          className="settings-input"
          value={sourceUrl}
          onChange={(e) => setSourceUrl(e.target.value)}
          placeholder="https://…"
        />
      </label>

      <label className="block text-sm">
        <span className="settings-label">
          Upload token{requiresToken ? " (required)" : " (optional)"}
        </span>
        <input
          className="settings-input"
          type="password"
          autoComplete="off"
          value={token}
          onChange={(e) => setToken(e.target.value)}
          placeholder="HOLLOWCADE_UPLOAD_TOKEN"
          required={requiresToken}
        />
      </label>

      <label className="flex items-center gap-2 text-sm">
        <input
          type="checkbox"
          checked={featured}
          onChange={(e) => setFeatured(e.target.checked)}
        />
        Feature on the home shelf
      </label>

      <div className="flex flex-wrap gap-2">
        <button type="submit" className="btn-primary" disabled={busy}>
          {busy ? "Uploading…" : "Add to public catalog"}
        </button>
        <Link href="/load" className="btn-ghost">
          Play local only instead
        </Link>
      </div>

      {err && (
        <p className="text-sm text-accent-hot whitespace-pre-wrap">{err}</p>
      )}
      {msg && <p className="text-sm text-amber whitespace-pre-wrap">{msg}</p>}
    </form>
  );
}
