"use client";

import { useEffect, useMemo, useState } from "react";
import Link from "next/link";
import EntryLink from "../components/EntryLink";
import { usePathname, useRouter } from "next/navigation";

type Item = {
  entryId: number;
  releaseSeq: number;
  entryTitle: string;
  year: number | null;
};

type Paged<T> = {
  items: T[];
  page: number;
  pageSize: number;
  total: number;
};

export default function ReleasesExplorer({
  initial,
  initialUrlState,
}: {
  initial?: Paged<Item>;
  initialUrlState?: {
    q: string;
    page: number;
    year: string;
    sort: "year_desc" | "year_asc" | "title" | "entry_id_desc";
    dLanguageId?: string;
    dMachinetypeId?: string; // keep as string for URL/state consistency
    filetypeId?: string;
    schemetypeId?: string;
    sourcetypeId?: string;
    casetypeId?: string;
    isDemo?: string; // "1" or "true"
  };
}) {
  const router = useRouter();
  const pathname = usePathname();

  const [q, setQ] = useState(initialUrlState?.q ?? "");
  const [page, setPage] = useState(initial?.page ?? initialUrlState?.page ?? 1);
  const [loading, setLoading] = useState(false);
  const [data, setData] = useState<Paged<Item> | null>(initial ?? null);
  const [year, setYear] = useState<string>(initialUrlState?.year ?? "");
  const [sort, setSort] = useState<"year_desc" | "year_asc" | "title" | "entry_id_desc">(initialUrlState?.sort ?? "year_desc");

  // Download-based filters and their option lists
  const [dLanguageId, setDLanguageId] = useState<string>(initialUrlState?.dLanguageId ?? "");
  const [dMachinetypeId, setDMachinetypeId] = useState<string>(initialUrlState?.dMachinetypeId ?? "");
  const [filetypeId, setFiletypeId] = useState<string>(initialUrlState?.filetypeId ?? "");
  const [schemetypeId, setSchemetypeId] = useState<string>(initialUrlState?.schemetypeId ?? "");
  const [sourcetypeId, setSourcetypeId] = useState<string>(initialUrlState?.sourcetypeId ?? "");
  const [casetypeId, setCasetypeId] = useState<string>(initialUrlState?.casetypeId ?? "");
  const [isDemo, setIsDemo] = useState<boolean>(!!(initialUrlState?.isDemo && (initialUrlState.isDemo === "1" || initialUrlState.isDemo === "true")));

  const [langs, setLangs] = useState<{ id: string; name: string }[]>([]);
  const [machines, setMachines] = useState<{ id: number; name: string }[]>([]);
  const [filetypes, setFiletypes] = useState<{ id: number; name: string }[]>([]);
  const [schemes, setSchemes] = useState<{ id: string; name: string }[]>([]);
  const [sources, setSources] = useState<{ id: string; name: string }[]>([]);
  const [cases, setCases] = useState<{ id: string; name: string }[]>([]);

  const pageSize = 20;
  const totalPages = useMemo(() => (data ? Math.max(1, Math.ceil(data.total / data.pageSize)) : 1), [data]);

  function updateUrl(nextPage = page) {
    const params = new URLSearchParams();
    if (q) params.set("q", q);
    params.set("page", String(nextPage));
    if (year) params.set("year", year);
    if (sort) params.set("sort", sort);
    if (dLanguageId) params.set("dLanguageId", dLanguageId);
    if (dMachinetypeId) params.set("dMachinetypeId", dMachinetypeId);
    if (filetypeId) params.set("filetypeId", filetypeId);
    if (schemetypeId) params.set("schemetypeId", schemetypeId);
    if (sourcetypeId) params.set("sourcetypeId", sourcetypeId);
    if (casetypeId) params.set("casetypeId", casetypeId);
    if (isDemo) params.set("isDemo", "1");
    const qs = params.toString();
    router.replace(qs ? `${pathname}?${qs}` : pathname);
  }

  async function fetchData(query: string, p: number) {
    setLoading(true);
    try {
      const params = new URLSearchParams();
      if (query) params.set("q", query);
      params.set("page", String(p));
      params.set("pageSize", String(pageSize));
      if (year) params.set("year", String(Number(year)));
      if (sort) params.set("sort", sort);
      if (dLanguageId) params.set("dLanguageId", dLanguageId);
      if (dMachinetypeId) params.set("dMachinetypeId", dMachinetypeId);
      if (filetypeId) params.set("filetypeId", filetypeId);
      if (schemetypeId) params.set("schemetypeId", schemetypeId);
      if (sourcetypeId) params.set("sourcetypeId", sourcetypeId);
      if (casetypeId) params.set("casetypeId", casetypeId);
      if (isDemo) params.set("isDemo", "1");
      const res = await fetch(`/api/zxdb/releases/search?${params.toString()}`);
      if (!res.ok) throw new Error(`Failed: ${res.status}`);
      const json: Paged<Item> = await res.json();
      setData(json);
    } catch (e) {
      console.error(e);
      setData({ items: [], page: 1, pageSize, total: 0 });
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    if (initial) {
      setData(initial);
      setPage(initial.page);
    }
  }, [initial]);

  useEffect(() => {
    const initialPage = initial?.page ?? 1;
    if (
      initial &&
      page === initialPage &&
      (initialUrlState?.q ?? "") === q &&
      (initialUrlState?.year ?? "") === (year ?? "") &&
      sort === (initialUrlState?.sort ?? "year_desc") &&
      (initialUrlState?.dLanguageId ?? "") === dLanguageId &&
      (initialUrlState?.dMachinetypeId ?? "") === dMachinetypeId &&
      (initialUrlState?.filetypeId ?? "") === filetypeId &&
      (initialUrlState?.schemetypeId ?? "") === schemetypeId &&
      (initialUrlState?.sourcetypeId ?? "") === sourcetypeId &&
      (initialUrlState?.casetypeId ?? "") === casetypeId &&
      (!!initialUrlState?.isDemo === isDemo)
    ) {
      updateUrl(page);
      return;
    }
    updateUrl(page);
    fetchData(q, page);
  }, [page, year, sort, dLanguageId, dMachinetypeId, filetypeId, schemetypeId, sourcetypeId, casetypeId, isDemo]);

  function onSubmit(e: React.FormEvent) {
    e.preventDefault();
    setPage(1);
    updateUrl(1);
    fetchData(q, 1);
  }

  // Load filter option lists on mount
  useEffect(() => {
    async function loadLists() {
      try {
        const [l, m, ft, sc, so, ca] = await Promise.all([
          fetch("/api/zxdb/languages", { cache: "force-cache" }).then((r) => r.json()),
          fetch("/api/zxdb/machinetypes", { cache: "force-cache" }).then((r) => r.json()),
          fetch("/api/zxdb/filetypes", { cache: "force-cache" }).then((r) => r.json()),
          fetch("/api/zxdb/schemetypes", { cache: "force-cache" }).then((r) => r.json()),
          fetch("/api/zxdb/sourcetypes", { cache: "force-cache" }).then((r) => r.json()),
          fetch("/api/zxdb/casetypes", { cache: "force-cache" }).then((r) => r.json()),
        ]);
        setLangs(l.items ?? []);
        setMachines(m.items ?? []);
        setFiletypes(ft.items ?? []);
        setSchemes(sc.items ?? []);
        setSources(so.items ?? []);
        setCases(ca.items ?? []);
      } catch {
        // ignore
      }
    }
    loadLists();
  }, []);

  const prevHref = useMemo(() => {
    const params = new URLSearchParams();
    if (q) params.set("q", q);
    params.set("page", String(Math.max(1, (data?.page ?? 1) - 1)));
    if (year) params.set("year", year);
    if (sort) params.set("sort", sort);
    if (dLanguageId) params.set("dLanguageId", dLanguageId);
    if (dMachinetypeId) params.set("dMachinetypeId", dMachinetypeId);
    if (filetypeId) params.set("filetypeId", filetypeId);
    if (schemetypeId) params.set("schemetypeId", schemetypeId);
    if (sourcetypeId) params.set("sourcetypeId", sourcetypeId);
    if (casetypeId) params.set("casetypeId", casetypeId);
    if (isDemo) params.set("isDemo", "1");
    return `/zxdb/releases?${params.toString()}`;
  }, [q, data?.page, year, sort, dLanguageId, dMachinetypeId, filetypeId, schemetypeId, sourcetypeId, casetypeId, isDemo]);

  const nextHref = useMemo(() => {
    const params = new URLSearchParams();
    if (q) params.set("q", q);
    params.set("page", String(Math.max(1, (data?.page ?? 1) + 1)));
    if (year) params.set("year", year);
    if (sort) params.set("sort", sort);
    if (dLanguageId) params.set("dLanguageId", dLanguageId);
    if (dMachinetypeId) params.set("dMachinetypeId", dMachinetypeId);
    if (filetypeId) params.set("filetypeId", filetypeId);
    if (schemetypeId) params.set("schemetypeId", schemetypeId);
    if (sourcetypeId) params.set("sourcetypeId", sourcetypeId);
    if (casetypeId) params.set("casetypeId", casetypeId);
    if (isDemo) params.set("isDemo", "1");
    return `/zxdb/releases?${params.toString()}`;
  }, [q, data?.page, year, sort, dLanguageId, dMachinetypeId, filetypeId, schemetypeId, sourcetypeId, casetypeId, isDemo]);

  return (
    <div>
      <h1 className="mb-3">Releases</h1>
      <form className="row gy-2 gx-2 align-items-center" onSubmit={onSubmit}>
        <div className="col-sm-8 col-md-6 col-lg-4">
          <input
            type="text"
            className="form-control"
            placeholder="Filter by entry title..."
            value={q}
            onChange={(e) => setQ(e.target.value)}
          />
        </div>
        <div className="col-auto">
          <button className="btn btn-primary" type="submit" disabled={loading}>Search</button>
        </div>
        <div className="col-auto">
          <input
            type="number"
            className="form-control"
            placeholder="Year"
            value={year}
            onChange={(e) => { setYear(e.target.value); setPage(1); }}
          />
        </div>
        <div className="col-auto">
          <select className="form-select" value={dLanguageId} onChange={(e) => { setDLanguageId(e.target.value); setPage(1); }}>
            <option value="">DL Language</option>
            {langs.map((l) => (
              <option key={l.id} value={l.id}>{l.name}</option>
            ))}
          </select>
        </div>
        <div className="col-auto">
          <select className="form-select" value={dMachinetypeId} onChange={(e) => { setDMachinetypeId(e.target.value); setPage(1); }}>
            <option value="">DL Machine</option>
            {machines.map((m) => (
              <option key={m.id} value={m.id}>{m.name}</option>
            ))}
          </select>
        </div>
        <div className="col-auto">
          <select className="form-select" value={filetypeId} onChange={(e) => { setFiletypeId(e.target.value); setPage(1); }}>
            <option value="">File type</option>
            {filetypes.map((ft) => (
              <option key={ft.id} value={ft.id}>{ft.name}</option>
            ))}
          </select>
        </div>
        <div className="col-auto">
          <select className="form-select" value={schemetypeId} onChange={(e) => { setSchemetypeId(e.target.value); setPage(1); }}>
            <option value="">Scheme</option>
            {schemes.map((s) => (
              <option key={s.id} value={s.id}>{s.name}</option>
            ))}
          </select>
        </div>
        <div className="col-auto">
          <select className="form-select" value={sourcetypeId} onChange={(e) => { setSourcetypeId(e.target.value); setPage(1); }}>
            <option value="">Source</option>
            {sources.map((s) => (
              <option key={s.id} value={s.id}>{s.name}</option>
            ))}
          </select>
        </div>
        <div className="col-auto">
          <select className="form-select" value={casetypeId} onChange={(e) => { setCasetypeId(e.target.value); setPage(1); }}>
            <option value="">Case</option>
            {cases.map((c) => (
              <option key={c.id} value={c.id}>{c.name}</option>
            ))}
          </select>
        </div>
        <div className="col-auto form-check ms-2">
          <input id="demoCheck" className="form-check-input" type="checkbox" checked={isDemo} onChange={(e) => { setIsDemo(e.target.checked); setPage(1); }} />
          <label className="form-check-label" htmlFor="demoCheck">Demo only</label>
        </div>
        <div className="col-auto">
          <select className="form-select" value={sort} onChange={(e) => { setSort(e.target.value as typeof sort); setPage(1); }}>
            <option value="year_desc">Sort: Newest</option>
            <option value="year_asc">Sort: Oldest</option>
            <option value="title">Sort: Title</option>
            <option value="entry_id_desc">Sort: Entry ID</option>
          </select>
        </div>
        {loading && (
          <div className="col-auto text-secondary">Loading...</div>
        )}
      </form>

      <div className="mt-3">
        {data && data.items.length === 0 && !loading && (
          <div className="alert alert-warning">No results.</div>
        )}
        {data && data.items.length > 0 && (
          <div className="table-responsive">
            <table className="table table-striped table-hover align-middle">
              <thead>
                <tr>
                  <th style={{width: 80}}>Entry ID</th>
                  <th>Title</th>
                  <th style={{width: 110}}>Release #</th>
                  <th style={{width: 100}}>Year</th>
                </tr>
              </thead>
              <tbody>
                {data.items.map((it) => (
                  <tr key={`${it.entryId}-${it.releaseSeq}`}>
                    <td>
                      <EntryLink id={it.entryId} />
                    </td>
                    <td>
                      <EntryLink id={it.entryId} title={it.entryTitle} />
                    </td>
                    <td>#{it.releaseSeq}</td>
                    <td>{it.year ?? <span className="text-secondary">-</span>}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        )}
      </div>

      <div className="d-flex align-items-center gap-2 mt-2">
        <span>
          Page {data?.page ?? 1} / {totalPages}
        </span>
        <div className="ms-auto d-flex gap-2">
          <Link
            className={`btn btn-outline-secondary ${!data || (data.page <= 1) ? "disabled" : ""}`}
            aria-disabled={!data || data.page <= 1}
            href={prevHref}
            onClick={(e) => {
              if (!data || data.page <= 1) return;
              e.preventDefault();
              setPage((p) => Math.max(1, p - 1));
            }}
          >
            Prev
          </Link>
          <Link
            className={`btn btn-outline-secondary ${!data || (data.page >= totalPages) ? "disabled" : ""}`}
            aria-disabled={!data || data.page >= totalPages}
            href={nextHref}
            onClick={(e) => {
              if (!data || data.page >= totalPages) return;
              e.preventDefault();
              setPage((p) => Math.min(totalPages, p + 1));
            }}
          >
            Next
          </Link>
        </div>
      </div>
    </div>
  );
}
