import { createServerFn } from "@tanstack/react-start";
import { useSession } from "@tanstack/react-start/server";
import { redirect } from "@tanstack/react-router";
import { createHash, timingSafeEqual } from "node:crypto";
import { z } from "zod";

export const RESOURCES = [
  "Ressource légendaire",
  "Rune",
  "Reflet onirique",
  "Point de rêve",
] as const;

type GateSession = { unlocked?: boolean };

function getSessionConfig() {
  return {
    password: process.env["SESSION_SECRET"]!,
    name: "songe-gate",
    maxAge: 60 * 60 * 24 * 30,
    cookie: {
      httpOnly: true,
      secure: true,
      sameSite: "lax" as const,
      path: "/",
    },
  };
}

function passwordMatches(input: string, expected: string): boolean {
  const a = createHash("sha256").update(input, "utf8").digest();
  const b = createHash("sha256").update(expected, "utf8").digest();
  return timingSafeEqual(a, b);
}

async function requireUnlocked() {
  const session = await useSession<GateSession>(getSessionConfig());
  if (!session.data.unlocked) throw redirect({ to: "/unlock" });
  return session;
}

export const unlockSite = createServerFn({ method: "POST" })
  .inputValidator((data: { password: string }) =>
    z.object({ password: z.string().min(1).max(200) }).parse(data),
  )
  .handler(async ({ data }) => {
    const expected = process.env["SITE_PASSWORD"];
    if (!expected) throw new Error("SITE_PASSWORD non configuré");
    if (!passwordMatches(data.password, expected)) return { ok: false as const };
    const session = await useSession<GateSession>(getSessionConfig());
    await session.update({ unlocked: true });
    return { ok: true as const };
  });

export const lockSite = createServerFn({ method: "POST" }).handler(async () => {
  const session = await useSession<GateSession>(getSessionConfig());
  await session.clear();
  return { ok: true as const };
});

export type Releve = {
  id: string;
  resource: string;
  valeur: number;
  releve_at: string;
  note: string | null;
};

export const listReleves = createServerFn({ method: "GET" }).handler(async () => {
  await requireUnlocked();
  const { supabaseAdmin } = await import("@/integrations/supabase/client.server");
  const { data, error } = await supabaseAdmin
    .from("releves")
    .select("id, resource, valeur, releve_at, note")
    .order("releve_at", { ascending: true });
  if (error) throw new Error(error.message);
  return (data ?? []).map((r) => ({ ...r, valeur: Number(r.valeur) })) as Releve[];
});

export const addReleve = createServerFn({ method: "POST" })
  .inputValidator((data: unknown) =>
    z
      .object({
        resource: z.enum(RESOURCES),
        valeur: z.number().finite(),
        releve_at: z.string().min(4).max(40),
        note: z.string().max(300).optional(),
      })
      .parse(data),
  )
  .handler(async ({ data }) => {
    await requireUnlocked();
    const { supabaseAdmin } = await import("@/integrations/supabase/client.server");
    const { error } = await supabaseAdmin.from("releves").insert({
      resource: data.resource,
      valeur: data.valeur,
      releve_at: new Date(data.releve_at).toISOString(),
      note: data.note?.trim() || null,
    });
    if (error) throw new Error(error.message);
    return { ok: true as const };
  });

export const deleteReleve = createServerFn({ method: "POST" })
  .inputValidator((data: unknown) => z.object({ id: z.string().uuid() }).parse(data))
  .handler(async ({ data }) => {
    await requireUnlocked();
    const { supabaseAdmin } = await import("@/integrations/supabase/client.server");
    const { error } = await supabaseAdmin.from("releves").delete().eq("id", data.id);
    if (error) throw new Error(error.message);
    return { ok: true as const };
  });
