"use client";

import { useMemo, useOptimistic, useState, useTransition } from "react";
import { useRouter } from "next/navigation";
import type { Acc } from "@/lib/types";
import { updateAccount } from "@/app/actions";
import EditableCell from "./editable-cell";

type Props = { initial: Acc[]; prefixPattern: string };

type SortDir = "asc" | "desc";
type OptimisticPatch = { username: string; field: keyof Acc; value: string };

function sortAccounts(rows: Acc[], dir: SortDir, prefix: string): Acc[] {
  return [...rows].sort((a, b) => {
    const ap = a.username.startsWith(prefix);
    const bp = b.username.startsWith(prefix);
    if (ap && !bp) return -1;
    if (!ap && bp) return 1;
    return dir === "asc"
      ? a.username.localeCompare(b.username)
      : b.username.localeCompare(a.username);
  });
}

function StatusBadge({ status }: { status: string }) {
  const map: Record<string, { bg: string; fg: string; label: string }> = {
    "": { bg: "bg-zinc-100", fg: "text-zinc-600", label: "available" },
    wait: { bg: "bg-amber-100", fg: "text-amber-800", label: "wait" },
    done: { bg: "bg-emerald-100", fg: "text-emerald-800", label: "done" },
  };
  const v = map[status] ?? { bg: "bg-zinc-100", fg: "text-zinc-600", label: status || "—" };
  return (
    <span
      className={`inline-flex items-center rounded-sm border border-current/10 ${v.bg} ${v.fg} px-1.5 py-0.5 font-mono text-[11px] font-semibold uppercase tracking-widest`}
    >
      {v.label}
    </span>
  );
}

export default function AccountsTable({ initial, prefixPattern }: Props) {
  const router = useRouter();
  const [sortDir, setSortDir] = useState<SortDir>("desc");
  const [editingKey, setEditingKey] = useState<string | null>(null);
  const [, startTransition] = useTransition();
  const [refreshing, setRefreshing] = useState(false);

  const [optimistic, applyOptimistic] = useOptimistic<Acc[], OptimisticPatch>(
    initial,
    (state, patch) =>
      state.map((row) =>
        row.username === patch.username ? { ...row, [patch.field]: patch.value } : row,
      ),
  );

  const sorted = useMemo(
    () => sortAccounts(optimistic, sortDir, prefixPattern),
    [optimistic, sortDir, prefixPattern],
  );

  function saveCell(username: string, field: keyof Acc, value: string) {
    return new Promise<{ ok: boolean; error?: string }>((resolve) => {
      startTransition(async () => {
        applyOptimistic({ username, field, value });
        const row = initial.find((r) => r.username === username);
        if (!row) {
          resolve({ ok: false, error: "row not found" });
          return;
        }
        const next: Acc = { ...row, [field]: value };
        const result = await updateAccount(next);
        if (result.ok) resolve({ ok: true });
        else resolve({ ok: false, error: result.error });
      });
    });
  }

  function refresh() {
    setRefreshing(true);
    startTransition(() => {
      router.refresh();
      setTimeout(() => setRefreshing(false), 400);
    });
  }

  if (initial.length === 0) {
    return (
      <div className="mx-auto max-w-3xl px-4 py-16">
        <h1 className="font-mono text-2xl font-bold uppercase tracking-tight text-zinc-900">
          Accounts
        </h1>
        <div className="mt-8 border-2 border-dashed border-zinc-300 bg-white p-10 text-center">
          <p className="font-mono text-sm text-zinc-500">
            No accounts yet. The monitor will create some on the next run.
          </p>
        </div>
      </div>
    );
  }

  return (
    <div className="mx-auto max-w-6xl px-4 py-8 sm:py-12">
      <div className="flex flex-wrap items-end justify-between gap-4">
        <div>
          <p className="font-mono text-[11px] font-bold uppercase tracking-[0.25em] text-zinc-500">
            // table
          </p>
          <h1 className="mt-1 font-mono text-2xl font-bold uppercase tracking-tight text-zinc-900 sm:text-3xl">
            Accounts
          </h1>
        </div>
        <div className="flex items-center gap-3">
          <div className="inline-flex items-baseline gap-2 border-2 border-zinc-900 bg-white px-3 py-1.5">
            <span className="font-mono text-[10px] font-bold uppercase tracking-[0.2em] text-zinc-500">
              count
            </span>
            <span className="font-mono text-lg font-bold text-zinc-900">
              {optimistic.length}
            </span>
          </div>
          <button
            type="button"
            onClick={refresh}
            disabled={refreshing}
            className="inline-flex items-center gap-1.5 border-2 border-zinc-900 bg-yellow-300 px-3 py-1.5 font-mono text-[11px] font-bold uppercase tracking-[0.2em] text-zinc-900 hover:bg-zinc-900 hover:text-yellow-300 disabled:opacity-60"
          >
            <span aria-hidden="true" className={refreshing ? "inline-block animate-spin" : ""}>
              ↻
            </span>
            refresh
          </button>
        </div>
      </div>

      <div className="mt-6 hidden border-2 border-zinc-900 bg-white sm:block">
        <table className="w-full table-fixed border-collapse">
          <thead>
            <tr className="border-b-2 border-zinc-900 bg-zinc-50">
              <th className="w-1/5 px-3 py-2 text-left">
                <button
                  type="button"
                  onClick={() => setSortDir((d) => (d === "asc" ? "desc" : "asc"))}
                  className="inline-flex items-center gap-1 font-mono text-[10px] font-bold uppercase tracking-[0.2em] text-zinc-700 hover:text-zinc-900"
                >
                  username
                  <span aria-hidden="true">{sortDir === "asc" ? "↑" : "↓"}</span>
                </button>
              </th>
              <th className="w-1/5 px-3 py-2 text-left font-mono text-[10px] font-bold uppercase tracking-[0.2em] text-zinc-700">
                password
              </th>
              <th className="w-[15%] px-3 py-2 text-left font-mono text-[10px] font-bold uppercase tracking-[0.2em] text-zinc-700">
                status
              </th>
              <th className="px-3 py-2 text-left font-mono text-[10px] font-bold uppercase tracking-[0.2em] text-zinc-700">
                link
              </th>
            </tr>
          </thead>
          <tbody>
            {sorted.map((row) => {
              const k = (f: string) => `${row.username}::${f}`;
              return (
                <tr
                  key={row.username}
                  className="border-b border-zinc-200 last:border-b-0 hover:bg-zinc-50"
                >
                  <td className="px-3 py-2 align-middle font-mono text-sm font-semibold text-zinc-900">
                    {row.username}
                  </td>
                  <td className="px-3 py-2 align-middle">
                    <EditableCell
                      value={row.password}
                      label={`password for ${row.username}`}
                      isCurrentlyEditing={editingKey === k("password")}
                      onEditStart={() => setEditingKey(k("password"))}
                      onEditEnd={() => setEditingKey(null)}
                      onSave={(v) => saveCell(row.username, "password", v)}
                    />
                  </td>
                  <td className="px-3 py-2 align-middle">
                    <div className="flex items-center gap-2">
                      <StatusBadge status={row.status} />
                      <EditableCell
                        value={row.status}
                        label={`status for ${row.username}`}
                        isCurrentlyEditing={editingKey === k("status")}
                        onEditStart={() => setEditingKey(k("status"))}
                        onEditEnd={() => setEditingKey(null)}
                        onSave={(v) => saveCell(row.username, "status", v)}
                      />
                    </div>
                  </td>
                  <td className="px-3 py-2 align-middle">
                    <EditableCell
                      value={row.link}
                      label={`link for ${row.username}`}
                      isCurrentlyEditing={editingKey === k("link")}
                      onEditStart={() => setEditingKey(k("link"))}
                      onEditEnd={() => setEditingKey(null)}
                      onSave={(v) => saveCell(row.username, "link", v)}
                    />
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>

      <div className="mt-6 space-y-3 sm:hidden">
        {sorted.map((row) => {
          const k = (f: string) => `${row.username}::${f}`;
          return (
            <div key={row.username} className="border-2 border-zinc-900 bg-white p-3">
              <div className="flex items-baseline justify-between">
                <span className="font-mono text-base font-bold text-zinc-900">{row.username}</span>
                <StatusBadge status={row.status} />
              </div>
              <dl className="mt-3 grid grid-cols-[max-content_1fr] items-baseline gap-x-3 gap-y-2 border-t border-zinc-200 pt-3">
                <dt className="font-mono text-[10px] font-bold uppercase tracking-[0.2em] text-zinc-500">
                  password
                </dt>
                <dd>
                  <EditableCell
                    value={row.password}
                    label={`password for ${row.username}`}
                    isCurrentlyEditing={editingKey === k("password")}
                    onEditStart={() => setEditingKey(k("password"))}
                    onEditEnd={() => setEditingKey(null)}
                    onSave={(v) => saveCell(row.username, "password", v)}
                  />
                </dd>
                <dt className="font-mono text-[10px] font-bold uppercase tracking-[0.2em] text-zinc-500">
                  status
                </dt>
                <dd>
                  <EditableCell
                    value={row.status}
                    label={`status for ${row.username}`}
                    isCurrentlyEditing={editingKey === k("status")}
                    onEditStart={() => setEditingKey(k("status"))}
                    onEditEnd={() => setEditingKey(null)}
                    onSave={(v) => saveCell(row.username, "status", v)}
                  />
                </dd>
                <dt className="font-mono text-[10px] font-bold uppercase tracking-[0.2em] text-zinc-500">
                  link
                </dt>
                <dd>
                  <EditableCell
                    value={row.link}
                    label={`link for ${row.username}`}
                    isCurrentlyEditing={editingKey === k("link")}
                    onEditStart={() => setEditingKey(k("link"))}
                    onEditEnd={() => setEditingKey(null)}
                    onSave={(v) => saveCell(row.username, "link", v)}
                  />
                </dd>
              </dl>
            </div>
          );
        })}
      </div>
    </div>
  );
}
