"use server";

import { db } from "@/db";
import { transactions } from "@/db/schema";
import { requireHousehold } from "@/lib/session";
import { revalidatePath } from "next/cache";
import { z } from "zod";
import Papa from "papaparse";

const ImportSchema = z.object({
  csv: z.string().min(1),
  bankAccountId: z.string().min(1),
});

type Row = Record<string, string>;

function parseAmount(s: string | undefined): number {
  if (!s) return 0;
  const cleaned = s.replace(/[^\d.\-]/g, "");
  const n = parseFloat(cleaned);
  return isNaN(n) ? 0 : Math.round(n * 100);
}

function parseDate(s: string | undefined): string | null {
  if (!s) return null;
  const trimmed = s.trim();
  // ISO
  const iso = /^(\d{4})-(\d{2})-(\d{2})/.exec(trimmed);
  if (iso) return `${iso[1]}-${iso[2]}-${iso[3]}`;
  // dd/mm/yyyy
  const dmy = /^(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/.exec(trimmed);
  if (dmy) {
    const d = String(dmy[1]).padStart(2, "0");
    const m = String(dmy[2]).padStart(2, "0");
    return `${dmy[3]}-${m}-${d}`;
  }
  // Month "May 9th"
  const md = /^([A-Za-z]+)\s+(\d{1,2})/.exec(trimmed);
  if (md) {
    const months: Record<string, number> = {
      jan: 1, feb: 2, mar: 3, apr: 4, may: 5, jun: 6,
      jul: 7, aug: 8, sep: 9, oct: 10, nov: 11, dec: 12,
    };
    const monKey = md[1].slice(0, 3).toLowerCase();
    const mon = months[monKey];
    if (!mon) return null;
    const day = String(parseInt(md[2], 10)).padStart(2, "0");
    const yr = new Date().getFullYear();
    return `${yr}-${String(mon).padStart(2, "0")}-${day}`;
  }
  return null;
}

export async function importCsvAction(formData: FormData) {
  const { householdId, user } = await requireHousehold();
  const parsed = ImportSchema.parse({
    csv: formData.get("csv"),
    bankAccountId: formData.get("bankAccountId"),
  });

  const result = Papa.parse<Row>(parsed.csv, { header: true, skipEmptyLines: true });
  if (result.errors.length > 0) throw new Error(result.errors[0].message);

  const inserts: typeof transactions.$inferInsert[] = [];
  for (const row of result.data) {
    const lower: Row = {};
    for (const [k, v] of Object.entries(row)) lower[k.trim().toLowerCase()] = String(v ?? "").trim();
    const date = parseDate(lower.date) ?? parseDate(lower.day);
    if (!date) continue;
    const description = lower.description || lower.desc || lower.memo || "";
    if (!description) continue;
    const inAmount = parseAmount(lower.in || lower.income || lower.credit);
    const outAmount = parseAmount(lower.out || lower.expense || lower.debit);
    let amountMinor = parseAmount(lower.amount);
    if (amountMinor === 0 && (inAmount || outAmount)) {
      amountMinor = inAmount - Math.abs(outAmount);
    }
    if (amountMinor === 0) continue;

    inserts.push({
      householdId,
      bankAccountId: parsed.bankAccountId,
      date,
      amountMinor,
      description,
      status: "posted",
      source: "import",
      createdByUserId: user.id,
    });
  }
  if (inserts.length > 0) await db.insert(transactions).values(inserts);

  revalidatePath("/ledger");
  revalidatePath("/");
}
