import { createFileRoute, useRouter } from "@tanstack/react-router";
import { useServerFn } from "@tanstack/react-start";
import { useMemo, useState } from "react";
import { Moon, Plus, Trash2, LogOut } from "lucide-react";
import {
  RESOURCES,
  addReleve,
  deleteReleve,
  listReleves,
  lockSite,
  type Releve,
} from "@/lib/gate.functions";

export const Route = createFileRoute("/")({
  head: () => ({
    meta: [
      { title: "Gains de ressources Songe — heure, jour, semaine" },
      {
        name: "description",
        content:
          "Suivi privé des ressources Songe : saisissez deux relevés datés et obtenez le gain par heure, par jour et par semaine.",
      },
      { property: "og:title", content: "Gains de ressources Songe" },
      {
        property: "og:description",
        content:
          "Calcul automatique des gains par heure, jour et semaine à partir de relevés datés.",
      },
    ],
  }),
  loader: () => listReleves(),
  errorComponent: ({ error }) => (
    <main className="flex min-h-screen items-center justify-center px-4">
      <p className="text-sm text-muted-foreground">{error.message}</p>
    </main>
  ),
  component: Dashboard,
});

function toLocalInput(d: Date) {
  const pad = (n: number) => String(n).padStart(2, "0");
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
}

const nf = new Intl.NumberFormat("fr-FR", { maximumFractionDigits: 2 });

type Stat = {
  resource: string;
  count: number;
  first: Releve;
  last: Releve;
  perHour: number;
  perDay: number;
  perWeek: number;
};

function computeStats(releves: Releve[]): Stat[] {
  return (RESOURCES as readonly string[]).map((resource): Stat | null => {
    const rows = releves
      .filter((r) => r.resource === resource)
      .sort(
        (a, b) => new Date(a.releve_at).getTime() - new Date(b.releve_at).getTime(),
      );
    if (rows.length < 2) return null;
    const first = rows[0]!;
    const last = rows[rows.length - 1]!;
    const hours =
      (new Date(last.releve_at).getTime() - new Date(first.releve_at).getTime()) /
      3_600_000;
    if (hours <= 0) return null;
    const perHour = (last.valeur - first.valeur) / hours;
    return {
      resource,
      count: rows.length,
      first,
      last,
      perHour,
      perDay: perHour * 24,
      perWeek: perHour * 24 * 7,
    } satisfies Stat;
  }).filter((s): s is Stat => s !== null);
}

function Dashboard() {
  const releves = Route.useLoaderData();
  const router = useRouter();
  const add = useServerFn(addReleve);
  const remove = useServerFn(deleteReleve);
  const lock = useServerFn(lockSite);

  const [resource, setResource] = useState<string>(RESOURCES[0] as string);
  const [valeur, setValeur] = useState("");
  const [date, setDate] = useState(() => toLocalInput(new Date()));
  const [note, setNote] = useState("");
  const [saving, setSaving] = useState(false);

  const stats = useMemo(() => computeStats(releves), [releves]);
  const sorted = useMemo(
    () =>
      [...releves].sort(
        (a, b) => new Date(b.releve_at).getTime() - new Date(a.releve_at).getTime(),
      ),
    [releves],
  );

  async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
    e.preventDefault();
    setSaving(true);
    try {
      await add({
        data: {
          resource: resource as (typeof RESOURCES)[number],
          valeur: Number(valeur),
          releve_at: new Date(date).toISOString(),
          note,
        },
      });
      setValeur("");
      setNote("");
      await router.invalidate();
    } finally {
      setSaving(false);
    }
  }

  return (
    <main className="mx-auto max-w-5xl px-4 py-10">
      <header className="flex flex-wrap items-center justify-between gap-4">
        <div className="flex items-center gap-3">
          <Moon className="size-6 text-primary" aria-hidden />
          <div>
            <h1 className="text-2xl font-semibold tracking-tight">
              Gains de ressources Songe
            </h1>
            <p className="text-sm text-muted-foreground">
              Deux relevés datés suffisent pour connaître le gain par heure, jour et
              semaine.
            </p>
          </div>
        </div>
        <button
          className="btn-songe-ghost"
          onClick={async () => {
            await lock({});
            await router.navigate({ to: "/unlock" });
          }}
        >
          <LogOut className="size-4" aria-hidden /> Verrouiller
        </button>
      </header>

      <section className="card-songe mt-8 p-6">
        <h2 className="text-lg font-semibold">Nouveau relevé</h2>
        <form
          onSubmit={onSubmit}
          className="mt-4 grid gap-4 sm:grid-cols-2 lg:grid-cols-5"
        >
          <label className="text-sm lg:col-span-2">
            <span className="text-muted-foreground">Ressource</span>
            <select
              className="input-songe mt-1"
              value={resource}
              onChange={(e) => setResource(e.target.value)}
            >
              {RESOURCES.map((r) => (
                <option key={r} value={r}>
                  {r}
                </option>
              ))}
            </select>
          </label>
          <label className="text-sm">
            <span className="text-muted-foreground">Total possédé</span>
            <input
              className="input-songe mt-1"
              type="number"
              step="any"
              required
              value={valeur}
              onChange={(e) => setValeur(e.target.value)}
              placeholder="0"
            />
          </label>
          <label className="text-sm">
            <span className="text-muted-foreground">Date et heure</span>
            <input
              className="input-songe mt-1"
              type="datetime-local"
              required
              value={date}
              onChange={(e) => setDate(e.target.value)}
            />
          </label>
          <label className="text-sm">
            <span className="text-muted-foreground">Note (option)</span>
            <input
              className="input-songe mt-1"
              maxLength={300}
              value={note}
              onChange={(e) => setNote(e.target.value)}
              placeholder="ex. après donjon"
            />
          </label>
          <div className="sm:col-span-2 lg:col-span-5">
            <button className="btn-songe" type="submit" disabled={saving}>
              <Plus className="size-4" aria-hidden />
              {saving ? "Enregistrement…" : "Enregistrer le relevé"}
            </button>
          </div>
        </form>
      </section>

      <section className="mt-8">
        <h2 className="text-lg font-semibold">Gains calculés</h2>
        {stats.length === 0 ? (
          <p className="mt-2 text-sm text-muted-foreground">
            Ajoutez au moins deux relevés d'une même ressource à deux dates
            différentes pour voir les gains.
          </p>
        ) : (
          <div className="mt-4 grid gap-4 md:grid-cols-2">
            {stats.map((s) => (
              <article key={s.resource} className="card-songe p-5">
                <h3 className="font-semibold text-primary">{s.resource}</h3>
                <p className="mt-1 text-xs text-muted-foreground">
                  {nf.format(s.first.valeur)} →{" "}
                  {nf.format(s.last.valeur)} entre le{" "}
                  {new Date(s.first.releve_at).toLocaleString("fr-FR")} et le{" "}
                  {new Date(s.last.releve_at).toLocaleString("fr-FR")}
                </p>
                <dl className="mt-4 grid grid-cols-3 gap-2 text-center">
                  {[
                    ["Par heure", s.perHour],
                    ["Par jour", s.perDay],
                    ["Par semaine", s.perWeek],
                  ].map(([label, value]) => (
                    <div
                      key={label as string}
                      className="rounded-md bg-secondary px-2 py-3"
                    >
                      <dt className="text-xs text-muted-foreground">{label}</dt>
                      <dd className="mt-1 text-lg font-semibold">
                        {nf.format(value as number)}
                      </dd>
                    </div>
                  ))}
                </dl>
              </article>
            ))}
          </div>
        )}
      </section>

      <section className="mt-8">
        <h2 className="text-lg font-semibold">Historique</h2>
        <div className="card-songe mt-4 overflow-x-auto">
          <table className="w-full text-sm">
            <thead className="text-left text-muted-foreground">
              <tr className="border-b border-border">
                <th className="px-4 py-3 font-medium">Date</th>
                <th className="px-4 py-3 font-medium">Ressource</th>
                <th className="px-4 py-3 font-medium">Total</th>
                <th className="px-4 py-3 font-medium">Note</th>
                <th className="px-4 py-3" />
              </tr>
            </thead>
            <tbody>
              {sorted.length === 0 && (
                <tr>
                  <td className="px-4 py-4 text-muted-foreground" colSpan={5}>
                    Aucun relevé pour le moment.
                  </td>
                </tr>
              )}
              {sorted.map((r) => (
                <tr key={r.id} className="border-b border-border/60 last:border-0">
                  <td className="px-4 py-3">
                    {new Date(r.releve_at).toLocaleString("fr-FR")}
                  </td>
                  <td className="px-4 py-3">{r.resource}</td>
                  <td className="px-4 py-3">{nf.format(r.valeur)}</td>
                  <td className="px-4 py-3 text-muted-foreground">{r.note ?? "—"}</td>
                  <td className="px-4 py-3 text-right">
                    <button
                      aria-label="Supprimer le relevé"
                      className="btn-songe-ghost"
                      onClick={async () => {
                        await remove({ data: { id: r.id } });
                        await router.invalidate();
                      }}
                    >
                      <Trash2 className="size-4" aria-hidden />
                    </button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </section>
    </main>
  );
}
