"use client";

import { useMemo, useRef, useState } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Badge } from "@/components/ui/badge";
import { useLocalStorage } from "@/lib/hooks/use-local-storage";
import { ALL_ORGANIZATIONS } from "@/lib/sag/entities";
import { formatCurrency } from "@/lib/utils";

const MAX_FILE_BYTES = 5 * 1024 * 1024; // 5 MB
const ACCEPT = ".pdf,application/pdf,image/*";

type Confidence = "high" | "medium" | "low";

interface ExtractedPaystub {
  employer: string;
  employerAddress?: string | null;
  payDate: string;
  payPeriodStart: string;
  payPeriodEnd: string;
  hoursRegular?: number | null;
  hoursOvertime?: number | null;
  hourlyRate?: number | null;
  grossPay: number;
  federalTaxWithheld?: number | null;
  stateTaxWithheld?: number | null;
  ficaWithheld?: number | null;
  medicareWithheld?: number | null;
  otherDeductions?: number | null;
  netPay: number;
  ytdGross?: number | null;
  ytdNet?: number | null;
  confidence: Confidence;
  rawNotes?: string | null;
}

// ---- Existing storage shapes (must match income-board.tsx) ------------------

type PayCadence = "weekly" | "biweekly" | "semimonthly" | "monthly" | "irregular";

interface StoredPaystub {
  id: string;
  date: string;
  gross: number;
  net?: number;
  hours?: number;
  notes?: string;
}

interface StoredIncomeSource {
  id: string;
  employerSlug: string;
  role?: string;
  cadence: PayCadence;
  payRate?: number;
  startedAt?: string;
  notes?: string;
  paystubs: StoredPaystub[];
}

// ---- Form-state shape (everything is a string for the inputs) ---------------

interface PaystubFormState {
  employer: string;
  payDate: string;
  payPeriodStart: string;
  payPeriodEnd: string;
  grossPay: string;
  netPay: string;
  hoursRegular: string;
  hoursOvertime: string;
  hourlyRate: string;
  federalTaxWithheld: string;
  stateTaxWithheld: string;
  ficaWithheld: string;
  medicareWithheld: string;
  otherDeductions: string;
  ytdGross: string;
  ytdNet: string;
  rawNotes: string;
  confidence: Confidence;
}

function extractedToForm(e: ExtractedPaystub): PaystubFormState {
  const numToStr = (v: number | null | undefined): string =>
    typeof v === "number" && Number.isFinite(v) ? String(v) : "";
  return {
    employer: e.employer ?? "",
    payDate: e.payDate ?? "",
    payPeriodStart: e.payPeriodStart ?? "",
    payPeriodEnd: e.payPeriodEnd ?? "",
    grossPay: numToStr(e.grossPay),
    netPay: numToStr(e.netPay),
    hoursRegular: numToStr(e.hoursRegular),
    hoursOvertime: numToStr(e.hoursOvertime),
    hourlyRate: numToStr(e.hourlyRate),
    federalTaxWithheld: numToStr(e.federalTaxWithheld),
    stateTaxWithheld: numToStr(e.stateTaxWithheld),
    ficaWithheld: numToStr(e.ficaWithheld),
    medicareWithheld: numToStr(e.medicareWithheld),
    otherDeductions: numToStr(e.otherDeductions),
    ytdGross: numToStr(e.ytdGross),
    ytdNet: numToStr(e.ytdNet),
    rawNotes: e.rawNotes ?? "",
    confidence: e.confidence,
  };
}

function buildNotesFromForm(f: PaystubFormState): string | undefined {
  const parts: string[] = [];
  if (f.payPeriodStart || f.payPeriodEnd) {
    parts.push(`Pay period ${f.payPeriodStart || "?"} - ${f.payPeriodEnd || "?"}`);
  }
  const totalHours =
    (Number(f.hoursRegular) || 0) + (Number(f.hoursOvertime) || 0);
  if (f.hoursRegular && f.hoursOvertime) {
    parts.push(`${f.hoursRegular} reg + ${f.hoursOvertime} OT hrs`);
  }
  if (f.hourlyRate) parts.push(`@ ${formatCurrency(Number(f.hourlyRate))}/hr`);
  const withholdings: string[] = [];
  if (f.federalTaxWithheld) withholdings.push(`Fed ${formatCurrency(Number(f.federalTaxWithheld))}`);
  if (f.stateTaxWithheld) withholdings.push(`State ${formatCurrency(Number(f.stateTaxWithheld))}`);
  if (f.ficaWithheld) withholdings.push(`FICA ${formatCurrency(Number(f.ficaWithheld))}`);
  if (f.medicareWithheld) withholdings.push(`Medicare ${formatCurrency(Number(f.medicareWithheld))}`);
  if (f.otherDeductions) withholdings.push(`Other ${formatCurrency(Number(f.otherDeductions))}`);
  if (withholdings.length > 0) parts.push(`Withheld: ${withholdings.join(", ")}`);
  if (f.ytdGross) parts.push(`YTD gross ${formatCurrency(Number(f.ytdGross))}`);
  if (f.ytdNet) parts.push(`YTD net ${formatCurrency(Number(f.ytdNet))}`);
  if (f.rawNotes) parts.push(f.rawNotes);
  if (!parts.length && !totalHours) return undefined;
  return parts.join(" | ") || undefined;
}

async function fileToBase64(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => {
      const result = reader.result;
      if (typeof result !== "string") {
        reject(new Error("Unexpected FileReader result"));
        return;
      }
      // Strip "data:<mime>;base64," prefix.
      const idx = result.indexOf(",");
      resolve(idx >= 0 ? result.slice(idx + 1) : result);
    };
    reader.onerror = () => reject(reader.error ?? new Error("FileReader failed"));
    reader.readAsDataURL(file);
  });
}

export function PaystubUpload() {
  const [sources, setSources] = useLocalStorage<StoredIncomeSource[]>(
    "sag.income.sources",
    []
  );
  const [status, setStatus] = useState<"idle" | "uploading" | "extracting" | "review" | "saved">(
    "idle"
  );
  const [error, setError] = useState<string | null>(null);
  const [savedMessage, setSavedMessage] = useState<string | null>(null);
  const [model, setModel] = useState<string | null>(null);
  const [confidence, setConfidence] = useState<Confidence | null>(null);
  const [form, setForm] = useState<PaystubFormState | null>(null);
  const [selectedSourceId, setSelectedSourceId] = useState<string>("");
  const [isDragging, setIsDragging] = useState(false);
  const fileInputRef = useRef<HTMLInputElement | null>(null);

  const sourceOptions = useMemo(() => {
    return sources.map((s) => {
      const org = ALL_ORGANIZATIONS.find((o) => o.slug === s.employerSlug);
      return {
        id: s.id,
        label: org ? `${org.emoji} ${org.name}` : s.employerSlug,
      };
    });
  }, [sources]);

  function resetAll() {
    setStatus("idle");
    setError(null);
    setForm(null);
    setSelectedSourceId("");
    setConfidence(null);
    setModel(null);
    if (fileInputRef.current) fileInputRef.current.value = "";
  }

  async function handleFile(file: File) {
    setError(null);
    setSavedMessage(null);

    if (file.size > MAX_FILE_BYTES) {
      setError(
        `File is too large (${(file.size / 1024 / 1024).toFixed(1)} MB). Max is 5 MB.`
      );
      return;
    }

    const mimeType = file.type || "application/pdf";
    const isPdf = mimeType === "application/pdf" || file.name.toLowerCase().endsWith(".pdf");
    const isImage = mimeType.startsWith("image/");
    if (!isPdf && !isImage) {
      setError(`Unsupported file type: ${mimeType || file.name}. Use PDF or an image.`);
      return;
    }

    setStatus("uploading");
    let base64: string;
    try {
      base64 = await fileToBase64(file);
    } catch (err) {
      setStatus("idle");
      setError(err instanceof Error ? err.message : "Failed to read file");
      return;
    }

    setStatus("extracting");
    try {
      const res = await fetch("/api/income/extract-paystub", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          inlineData: base64,
          inlineMimeType: isPdf ? "application/pdf" : mimeType,
        }),
      });
      const json = (await res.json()) as
        | { ok: true; extracted: ExtractedPaystub; model: string }
        | { ok: false; error: string };
      if (!json.ok) {
        setStatus("idle");
        setError(json.error || `Extraction failed (HTTP ${res.status})`);
        return;
      }
      setForm(extractedToForm(json.extracted));
      setConfidence(json.extracted.confidence);
      setModel(json.model);
      setStatus("review");
    } catch (err) {
      setStatus("idle");
      setError(err instanceof Error ? err.message : "Network error during extraction");
    }
  }

  function onDrop(e: React.DragEvent<HTMLDivElement>) {
    e.preventDefault();
    setIsDragging(false);
    const file = e.dataTransfer.files?.[0];
    if (file) void handleFile(file);
  }

  function save() {
    if (!form) return;
    if (!selectedSourceId) {
      setError("Pick an income source to save this paystub under.");
      return;
    }
    const gross = Number(form.grossPay);
    if (!form.payDate || !Number.isFinite(gross) || gross <= 0) {
      setError("Pay date and a positive gross amount are required.");
      return;
    }
    const net = form.netPay ? Number(form.netPay) : undefined;
    const totalHours =
      (Number(form.hoursRegular) || 0) + (Number(form.hoursOvertime) || 0);
    const stub: StoredPaystub = {
      id: `stub-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
      date: form.payDate,
      gross,
      net: net != null && Number.isFinite(net) ? net : undefined,
      hours: totalHours > 0 ? totalHours : undefined,
      notes: buildNotesFromForm(form),
    };

    let savedToLabel = "";
    setSources((prev) =>
      prev.map((s) => {
        if (s.id !== selectedSourceId) return s;
        const org = ALL_ORGANIZATIONS.find((o) => o.slug === s.employerSlug);
        savedToLabel = org?.name ?? s.employerSlug;
        return {
          ...s,
          paystubs: [...s.paystubs, stub].sort((a, b) => b.date.localeCompare(a.date)),
        };
      })
    );

    setSavedMessage(`Saved to ${savedToLabel || "income source"}. Visible on this page.`);
    setStatus("saved");
    setForm(null);
    setSelectedSourceId("");
    setError(null);
    if (fileInputRef.current) fileInputRef.current.value = "";
  }

  const dropZoneClasses = [
    "rounded-md border-2 border-dashed p-6 text-center transition-colors cursor-pointer",
    isDragging
      ? "border-[var(--sag-brand)] bg-[var(--sag-brand)]/5"
      : "border-input bg-muted/30 hover:bg-muted/50",
  ].join(" ");

  const isBusy = status === "uploading" || status === "extracting";

  return (
    <Card>
      <CardContent className="p-6 space-y-4">
        <div className="flex items-start justify-between flex-wrap gap-2">
          <div>
            <h2 className="text-base font-semibold">Upload paystub (auto-extract)</h2>
            <p className="mt-1 text-sm text-muted-foreground max-w-2xl">
              Drop a paystub PDF or photo. Claude reads it, fills in gross / net / hours /
              pay period, you review, then save it to the right income source.
            </p>
          </div>
          {model && (
            <Badge variant="outline" className="text-[10px]">
              Model: {model}
            </Badge>
          )}
        </div>

        {savedMessage && status === "saved" && (
          <div className="rounded-md border border-green-300 bg-green-50 dark:bg-green-950/30 dark:border-green-900 px-3 py-2 text-sm text-green-800 dark:text-green-300 flex items-center justify-between gap-2">
            <span>{savedMessage}</span>
            <Button variant="ghost" size="sm" onClick={resetAll}>
              Upload another
            </Button>
          </div>
        )}

        {error && (
          <div className="rounded-md border border-destructive/40 bg-destructive/5 px-3 py-2 text-sm text-destructive">
            {error}
          </div>
        )}

        {status !== "review" && status !== "saved" && (
          <div
            role="button"
            tabIndex={0}
            aria-disabled={isBusy}
            className={dropZoneClasses}
            onClick={() => !isBusy && fileInputRef.current?.click()}
            onKeyDown={(e) => {
              if ((e.key === "Enter" || e.key === " ") && !isBusy) {
                e.preventDefault();
                fileInputRef.current?.click();
              }
            }}
            onDragOver={(e) => {
              e.preventDefault();
              if (!isBusy) setIsDragging(true);
            }}
            onDragLeave={() => setIsDragging(false)}
            onDrop={onDrop}
          >
            <div className="text-3xl mb-2">📄</div>
            <p className="text-sm font-medium">
              {isBusy
                ? status === "uploading"
                  ? "Reading file..."
                  : "Extracting paystub fields..."
                : "Drop a paystub here or click to choose a file"}
            </p>
            <p className="mt-1 text-xs text-muted-foreground">
              PDF or image up to 5 MB. Your file is sent to Claude for one-shot extraction.
            </p>
            <input
              ref={fileInputRef}
              type="file"
              accept={ACCEPT}
              className="hidden"
              onChange={(e) => {
                const file = e.target.files?.[0];
                if (file) void handleFile(file);
              }}
            />
          </div>
        )}

        {status === "review" && form && (
          <ReviewForm
            form={form}
            confidence={confidence}
            setForm={setForm}
            sourceOptions={sourceOptions}
            selectedSourceId={selectedSourceId}
            setSelectedSourceId={setSelectedSourceId}
            onSave={save}
            onCancel={resetAll}
            sourcesEmpty={sources.length === 0}
          />
        )}
      </CardContent>
    </Card>
  );
}

function ReviewForm({
  form,
  confidence,
  setForm,
  sourceOptions,
  selectedSourceId,
  setSelectedSourceId,
  onSave,
  onCancel,
  sourcesEmpty,
}: {
  form: PaystubFormState;
  confidence: Confidence | null;
  setForm: (f: PaystubFormState) => void;
  sourceOptions: { id: string; label: string }[];
  selectedSourceId: string;
  setSelectedSourceId: (id: string) => void;
  onSave: () => void;
  onCancel: () => void;
  sourcesEmpty: boolean;
}) {
  const update = (patch: Partial<PaystubFormState>) => setForm({ ...form, ...patch });

  const confidenceBadge =
    confidence === "high" ? (
      <Badge variant="success">High confidence</Badge>
    ) : confidence === "medium" ? (
      <Badge variant="warning">Medium confidence</Badge>
    ) : confidence === "low" ? (
      <Badge variant="destructive">Low confidence — please double-check</Badge>
    ) : null;

  return (
    <div className="space-y-4">
      <div className="flex items-center justify-between flex-wrap gap-2">
        <div className="flex items-center gap-2">
          <h3 className="text-sm font-semibold">Review extracted fields</h3>
          {confidenceBadge}
        </div>
        <Button variant="ghost" size="sm" onClick={onCancel}>
          Cancel
        </Button>
      </div>

      <div className="grid gap-3 md:grid-cols-3">
        <Field label="Employer (from paystub)">
          <Input
            value={form.employer}
            onChange={(e) => update({ employer: e.target.value })}
            placeholder="Employer name"
          />
        </Field>
        <Field label="Pay date">
          <Input
            type="date"
            value={form.payDate}
            onChange={(e) => update({ payDate: e.target.value })}
          />
        </Field>
        <Field label="Gross pay">
          <Input
            type="number"
            step="0.01"
            value={form.grossPay}
            onChange={(e) => update({ grossPay: e.target.value })}
            placeholder="0.00"
          />
        </Field>

        <Field label="Pay period start">
          <Input
            type="date"
            value={form.payPeriodStart}
            onChange={(e) => update({ payPeriodStart: e.target.value })}
          />
        </Field>
        <Field label="Pay period end">
          <Input
            type="date"
            value={form.payPeriodEnd}
            onChange={(e) => update({ payPeriodEnd: e.target.value })}
          />
        </Field>
        <Field label="Net pay">
          <Input
            type="number"
            step="0.01"
            value={form.netPay}
            onChange={(e) => update({ netPay: e.target.value })}
            placeholder="0.00"
          />
        </Field>

        <Field label="Regular hours">
          <Input
            type="number"
            step="0.25"
            value={form.hoursRegular}
            onChange={(e) => update({ hoursRegular: e.target.value })}
            placeholder="0"
          />
        </Field>
        <Field label="Overtime hours">
          <Input
            type="number"
            step="0.25"
            value={form.hoursOvertime}
            onChange={(e) => update({ hoursOvertime: e.target.value })}
            placeholder="0"
          />
        </Field>
        <Field label="Hourly rate">
          <Input
            type="number"
            step="0.01"
            value={form.hourlyRate}
            onChange={(e) => update({ hourlyRate: e.target.value })}
            placeholder="0.00"
          />
        </Field>

        <Field label="Federal tax withheld">
          <Input
            type="number"
            step="0.01"
            value={form.federalTaxWithheld}
            onChange={(e) => update({ federalTaxWithheld: e.target.value })}
            placeholder="0.00"
          />
        </Field>
        <Field label="State tax withheld">
          <Input
            type="number"
            step="0.01"
            value={form.stateTaxWithheld}
            onChange={(e) => update({ stateTaxWithheld: e.target.value })}
            placeholder="0.00"
          />
        </Field>
        <Field label="FICA withheld">
          <Input
            type="number"
            step="0.01"
            value={form.ficaWithheld}
            onChange={(e) => update({ ficaWithheld: e.target.value })}
            placeholder="0.00"
          />
        </Field>

        <Field label="Medicare withheld">
          <Input
            type="number"
            step="0.01"
            value={form.medicareWithheld}
            onChange={(e) => update({ medicareWithheld: e.target.value })}
            placeholder="0.00"
          />
        </Field>
        <Field label="Other deductions">
          <Input
            type="number"
            step="0.01"
            value={form.otherDeductions}
            onChange={(e) => update({ otherDeductions: e.target.value })}
            placeholder="0.00"
          />
        </Field>
        <Field label="YTD gross">
          <Input
            type="number"
            step="0.01"
            value={form.ytdGross}
            onChange={(e) => update({ ytdGross: e.target.value })}
            placeholder="0.00"
          />
        </Field>

        <Field label="YTD net" className="md:col-span-1">
          <Input
            type="number"
            step="0.01"
            value={form.ytdNet}
            onChange={(e) => update({ ytdNet: e.target.value })}
            placeholder="0.00"
          />
        </Field>
        <Field label="Notes" className="md:col-span-2">
          <Input
            value={form.rawNotes}
            onChange={(e) => update({ rawNotes: e.target.value })}
            placeholder="Anything Claude flagged or you want to remember"
          />
        </Field>
      </div>

      <div className="rounded-md border bg-muted/20 p-4 space-y-2">
        <label className="text-xs text-muted-foreground">
          Income source to save under
        </label>
        {sourcesEmpty ? (
          <p className="text-sm text-muted-foreground">
            No income sources yet. Scroll down to the &ldquo;Suggested employers&rdquo;
            section or use &ldquo;+ Add income source&rdquo; below, then come back to upload.
          </p>
        ) : (
          <select
            value={selectedSourceId}
            onChange={(e) => setSelectedSourceId(e.target.value)}
            className="w-full h-10 rounded-md border border-input bg-background px-3 text-sm"
          >
            <option value="">— Pick an income source —</option>
            {sourceOptions.map((opt) => (
              <option key={opt.id} value={opt.id}>
                {opt.label}
              </option>
            ))}
          </select>
        )}
      </div>

      <div className="flex justify-end gap-2">
        <Button variant="ghost" size="sm" onClick={onCancel}>
          Discard
        </Button>
        <Button
          variant="brand"
          size="sm"
          onClick={onSave}
          disabled={sourcesEmpty || !selectedSourceId}
        >
          Save paystub to source
        </Button>
      </div>
    </div>
  );
}

function Field({
  label,
  children,
  className,
}: {
  label: string;
  children: React.ReactNode;
  className?: string;
}) {
  return (
    <div className={className}>
      <label className="text-xs text-muted-foreground">{label}</label>
      <div className="mt-1">{children}</div>
    </div>
  );
}
