import { useCallback, useState } from "react";
import { parse, type ParseResult } from "papaparse";
import { format, parse as parseDate } from "date-fns";
import { useMutation, useQuery } from "convex/react";
import { api } from "../../../convex/_generated/api";
import type { Id } from "../../../convex/_generated/dataModel";
import { categorize, parseCounterpartyFromBuchungstext, parseGermanAmount } from "@convex-lib/categorize";
import { resolveAssignedAndEffective } from "@convex-lib/month";
import { computeDedupHash } from "@convex-lib/comdirectMap";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { ImportPreviewTable, type PreviewRow } from "./ImportPreviewTable";
import { toast } from "sonner";

const HEADER = "Buchungstag;Wertstellung (Valuta);Vorgang;Buchungstext;Umsatz in EUR";

function parseComdirectCsv(text: string): Array<Record<string, string>> {
  const lines = text.split(/\r?\n/);
  const rows: Array<Record<string, string>> = [];
  let inBlock = false;

  for (const line of lines) {
    if (line.trim() === HEADER) {
      inBlock = true;
      continue;
    }
    if (!inBlock) continue;
    if (
      !line.trim() ||
      line.startsWith("Alter Kontostand") ||
      line.startsWith("Neuer Kontostand") ||
      line.startsWith("Umsätze") ||
      line.startsWith("Keine Umsätze")
    ) {
      inBlock = false;
      continue;
    }
    const parsed: ParseResult<string[]> = parse(line, { delimiter: ";", quoteChar: '"' });
    const fields = parsed.data[0];
    if (!fields || fields.length < 5) continue;
    rows.push({
      buchungstag: fields[0],
      valuta: fields[1],
      vorgang: fields[2],
      buchungstext: fields[3],
      betrag: fields[4],
    });
  }
  return rows;
}

export function CsvImportWizard() {
  const accounts = useQuery(api.accounts.list);
  const settings = useQuery(api.settings.get);
  const categories = useQuery(api.categories.list);
  const commitRows = useMutation(api.imports.commitRows);

  const [step, setStep] = useState<"upload" | "preview" | "done">("upload");
  const [filename, setFilename] = useState("");
  const [accountId, setAccountId] = useState<string>();
  const [rows, setRows] = useState<PreviewRow[]>([]);
  const [result, setResult] = useState<{ imported: number; skipped: number } | null>(null);

  const processFile = useCallback(
    async (file: File) => {
      const buffer = await file.arrayBuffer();
      const text = new TextDecoder("iso-8859-1").decode(buffer);
      const parsed = parseComdirectCsv(text);
      const ownNames = settings?.ownNames ?? [];
      const salaryShift = settings?.salaryShift ?? {
        enabled: true,
        categoryNames: ["Gehalt & Besoldung"],
        dayThreshold: 25,
      };

      const preview: PreviewRow[] = [];
      for (const row of parsed) {
        const isPending = row.buchungstag.trim().toLowerCase() === "offen";
        let bookingDate: string | undefined;
        if (!isPending) {
          const d = parseDate(row.buchungstag, "dd.MM.yyyy", new Date());
          bookingDate = format(d, "yyyy-MM-dd");
        }
        const amount = parseGermanAmount(row.betrag);
        const { counterparty, description, rawText } = parseCounterpartyFromBuchungstext(row.buchungstext);
        const categoryName = categorize(rawText, amount, row.vorgang, ownNames);
        const { assignedMonth, effectiveMonth } = resolveAssignedAndEffective(
          bookingDate,
          amount,
          categoryName,
          salaryShift,
        );
        const dedupHash = await computeDedupHash({
          accountId,
          bookingDate,
          amount,
          description,
          vorgang: row.vorgang,
        });
        preview.push({
          bookingDate,
          valueDate: row.valuta
            ? format(parseDate(row.valuta, "dd.MM.yyyy", new Date()), "yyyy-MM-dd")
            : undefined,
          description,
          counterparty,
          amount,
          vorgang: row.vorgang,
          isPending,
          rawText,
          categoryName,
          assignedMonth,
          effectiveMonth,
          dedupHash,
        });
      }
      setRows(preview);
      setFilename(file.name);
      setStep("preview");
    },
    [settings, accountId],
  );

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    const file = e.dataTransfer.files[0];
    if (file) void processFile(file);
  };

  const handleCommit = async () => {
    if (!accountId) {
      toast.error("Bitte Konto wählen");
      return;
    }
    const res = await commitRows({
      filename,
      source: "comdirect-csv",
      accountId: accountId as Id<"accounts">,
      rows: rows.map((r) => ({
        bookingDate: r.bookingDate,
        valueDate: r.valueDate,
        description: r.description,
        counterparty: r.counterparty,
        amount: r.amount,
        vorgang: r.vorgang,
        isPending: r.isPending,
        rawText: r.rawText,
        categoryName: r.categoryName,
        assignedMonth: r.assignedMonth,
        effectiveMonth: r.effectiveMonth,
        dedupHash: r.dedupHash,
        categoryId: categories?.find((c) => c.name === r.categoryName)?._id,
      })),
    });
    setResult({ imported: res.importedCount, skipped: res.skippedCount });
    setStep("done");
    toast.success(`${res.importedCount} importiert, ${res.skippedCount} übersprungen`);
  };

  if (step === "upload") {
    return (
      <Card>
        <CardHeader>
          <CardTitle>CSV-Import (comdirect)</CardTitle>
        </CardHeader>
        <CardContent className="space-y-4">
          <div
            className="flex min-h-40 cursor-pointer flex-col items-center justify-center rounded-lg border border-dashed p-8 text-center"
            onDragOver={(e) => e.preventDefault()}
            onDrop={handleDrop}
          >
            <p className="mb-2 text-sm text-muted-foreground">
              comdirect-CSV hier ablegen (ISO-8859-1, Semikolon)
            </p>
            <input
              type="file"
              accept=".csv,.CSV"
              onChange={(e) => e.target.files?.[0] && void processFile(e.target.files[0])}
            />
          </div>
        </CardContent>
      </Card>
    );
  }

  if (step === "preview") {
    return (
      <div className="space-y-4">
        <div className="flex flex-wrap gap-2">
          <Select value={accountId} onValueChange={setAccountId}>
            <SelectTrigger className="w-[220px]">
              <SelectValue placeholder="Konto wählen" />
            </SelectTrigger>
            <SelectContent>
              {accounts?.map((a) => (
                <SelectItem key={a._id} value={a._id}>
                  {a.name}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
          <Button onClick={handleCommit}>Import starten</Button>
          <Button variant="outline" onClick={() => setStep("upload")}>
            Zurück
          </Button>
        </div>
        <ImportPreviewTable rows={rows} onRowsChange={setRows} categories={categories ?? []} />
      </div>
    );
  }

  return (
    <Card>
      <CardContent className="pt-6">
        <p>
          Import abgeschlossen: {result?.imported} Buchungen importiert, {result?.skipped} übersprungen.
        </p>
        <Button className="mt-4" onClick={() => setStep("upload")}>
          Weiteren Import starten
        </Button>
      </CardContent>
    </Card>
  );
}
