/**
 * Chart persistence + sharing helpers.
 *
 * Charts are stored as { input, label, fullName } — we re-run buildChart()
 * on read so a Phase 1 schema bump doesn't force a re-save. The Prisma
 * `computedJson` cache is populated on save with the rendered output so
 * cold reads skip the engine if input hasn't changed; tu-vi-tron-doi
 * still recomputes from URL params for unsaved viewing.
 */
import { randomBytes } from "node:crypto";
import { headers } from "next/headers";
import { auth } from "@/lib/auth";
import { buildChart, type ChartInput } from "@/lib/tuvi/engine";

export type StoredChart = {
  id: string;
  label: string;
  fullName: string;
  birthDate: Date;
  birthTime: string;
  gender: string;
  isLunar: boolean;
  shareToken: string | null;
  isDefault: boolean;
  createdAt: Date;
  updatedAt: Date;
};

/** Resolve the current logged-in user, or null. */
export async function currentUser(): Promise<{ id: string; email: string; name: string } | null> {
  const session = await auth.api.getSession({ headers: await headers() });
  if (!session?.user) return null;
  return {
    id: session.user.id,
    email: session.user.email,
    name: session.user.name ?? "",
  };
}

/** Generate a 22-char URL-safe random token. ~131 bits — plenty for share links. */
export function newShareToken(): string {
  // 16 bytes = 128 bits = 22 base64url chars
  return randomBytes(16).toString("base64url");
}

/** Reconstruct a ChartInput from a stored row + run buildChart. */
export function chartInputFrom(stored: StoredChart): ChartInput {
  // birthTime is stored as "HH:MM" — convert to timeIndex 0..12 (giờ Tý → giờ Hợi)
  const [hStr, mStr] = stored.birthTime.split(":");
  const h = parseInt(hStr ?? "0", 10);
  const m = parseInt(mStr ?? "0", 10);
  // Combine into decimal hour: 23:00..00:59 = giờ Tý (idx 0); thereafter every 2h.
  const dec = h + m / 60;
  // 23..1 → 0 (Tý); 1..3 → 1 (Sửu); 3..5 → 2 (Dần); ...; 21..23 → 11 (Hợi)
  // Special case 12 (giờ Tý sớm — chính giờ 0:00). Engine accepts 0..12 where
  // 12 means "early Tý" (0:00–1:00). For round-tripping HH:MM we don't need
  // 12; treat 23:00–24:00 as standard Tý (0).
  const timeIndex =
    dec >= 23 || dec < 1
      ? 0
      : dec < 3
        ? 1
        : dec < 5
          ? 2
          : dec < 7
            ? 3
            : dec < 9
              ? 4
              : dec < 11
                ? 5
                : dec < 13
                  ? 6
                  : dec < 15
                    ? 7
                    : dec < 17
                      ? 8
                      : dec < 19
                        ? 9
                        : dec < 21
                          ? 10
                          : 11;

  return {
    date: stored.birthDate.toISOString().slice(0, 10),
    timeIndex,
    gender: stored.gender === "FEMALE" ? "Nữ" : "Nam",
    calendar: stored.isLunar ? "lunar" : "solar",
    isLeapMonth: false,
    fullName: stored.fullName,
  };
}

/** Build a Chart from a stored row. Cheap if no schema bump since save. */
export function renderStoredChart(stored: StoredChart) {
  return buildChart(chartInputFrom(stored));
}

/** Map ChartInput to Prisma create payload. */
export function inputToPersist(input: ChartInput, label: string) {
  // Convert timeIndex (0..12) to a representative HH:MM. We pick the START
  // of each Chinese-hour window. timeIndex 0 = giờ Tý 23:00 (use 23:00 to
  // signal "previous day Tý"; alt is 00:00 for standard Tý — 23:00 keeps
  // 12-window encoding distinguishable from index 0 vs midnight ambiguity).
  const HH = [23, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21][input.timeIndex] ?? 0;
  const birthTime = `${String(HH).padStart(2, "0")}:00`;
  return {
    label,
    fullName: input.fullName ?? label,
    birthDate: new Date(input.date + "T00:00:00.000Z"),
    birthTime,
    gender: input.gender === "Nữ" ? ("FEMALE" as const) : ("MALE" as const),
    isLunar: input.calendar === "lunar",
  };
}

/** Encode a ChartInput as URL search params (for /tu-vi-tron-doi?d=...). */
export function inputToSearchParams(input: ChartInput): URLSearchParams {
  const sp = new URLSearchParams({
    d: input.date,
    t: String(input.timeIndex),
    g: input.gender,
    c: input.calendar,
  });
  if (input.fullName) sp.set("n", input.fullName);
  if (input.isLeapMonth) sp.set("leap", "1");
  return sp;
}

/** Reverse of inputToPersist + chartInputFrom: get rough HH:MM from index. */
export const TIME_INDEX_LABELS = [
  "Tý (23:00–01:00)",
  "Sửu (01:00–03:00)",
  "Dần (03:00–05:00)",
  "Mão (05:00–07:00)",
  "Thìn (07:00–09:00)",
  "Tỵ (09:00–11:00)",
  "Ngọ (11:00–13:00)",
  "Mùi (13:00–15:00)",
  "Thân (15:00–17:00)",
  "Dậu (17:00–19:00)",
  "Tuất (19:00–21:00)",
  "Hợi (21:00–23:00)",
];
