"use client";

import { useMemo, useState } from "react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { BILL_CATEGORIES } from "@/lib/finance/bill-types";
import { ALL_ORGANIZATIONS } from "@/lib/sag/entities";
import { formatCurrency } from "@/lib/utils";
import {
  evenPercentages,
  newPartId,
  validateSplit,
  type SplitErrorField,
  type SplitValidationError,
  type TxnSplit,
  type TxnSplitPart,
} from "@/lib/finance/txn-splits";

export interface SplitTxnDialogTxn {
  transactionId: string;
  amount: number;
  merchantName: string;
}

interface Props {
  txn: SplitTxnDialogTxn;
  /** Existing split to pre-populate; undefined for a fresh split. */
  existing?: TxnSplit;
  onSave: (parts: TxnSplitPart[]) => void;
  onCancel: () => void;
}

function emptyPart(): TxnSplitPart {
  return { id: newPartId(), percentage: 0 };
}

function defaultParts(): TxnSplitPart[] {
  const shares = evenPercentages(2);
  return [
    { id: newPartId(), percentage: shares[0] },
    { id: newPartId(), percentage: shares[1] },
  ];
}

export function SplitTxnDialog({ txn, existing, onSave, onCancel }: Props) {
  const [parts, setParts] = useState<TxnSplitPart[]>(() =>
    existing && existing.parts.length > 0
      ? existing.parts.map((p) => ({ ...p }))
      : defaultParts()
  );

  const errors = useMemo(() => validateSplit(parts), [parts]);
  const errorsByPart = useMemo(() => {
    const map: Record<string, SplitValidationError[]> = {};
    for (const e of errors) {
      if (!e.partId) continue;
      const list = map[e.partId] ?? [];
      list.push(e);
      map[e.partId] = list;
    }
    return map;
  }, [errors]);
  const globalErrors = useMemo(() => errors.filter((e) => !e.partId), [errors]);

  const sum = useMemo(
    () => parts.reduce((s, p) => s + (Number.isFinite(p.percentage) ? p.percentage : 0), 0),
    [parts]
  );
  const sumOk = Math.abs(sum - 100) <= 0.01;
  const canSave = errors.length === 0;

  function updatePart(id: string, patch: Partial<TxnSplitPart>) {
    setParts((prev) => prev.map((p) => (p.id === id ? { ...p, ...patch } : p)));
  }

  function addPart() {
    setParts((prev) => [...prev, emptyPart()]);
  }

  function removePart(id: string) {
    setParts((prev) => (prev.length <= 1 ? prev : prev.filter((p) => p.id !== id)));
  }

  function autoDistribute() {
    setParts((prev) => {
      const shares = evenPercentages(prev.length);
      return prev.map((p, i) => ({ ...p, percentage: shares[i] ?? 0 }));
    });
  }

  function handleSave() {
    if (!canSave) return;
    onSave(parts);
  }

  const absAmount = Math.abs(txn.amount);

  return (
    <div
      role="region"
      aria-label={`Split transaction at ${txn.merchantName}`}
      className="rounded-md border border-input bg-muted/30 p-4"
    >
      <div className="flex items-start justify-between gap-3 mb-3">
        <div>
          <h4 className="text-sm font-semibold">
            Split transaction {formatCurrency(absAmount)} &mdash; {txn.merchantName}
          </h4>
          <p className="text-xs text-muted-foreground mt-0.5">
            Allocate this debit across entities or categories. Percentages must sum to 100.
          </p>
        </div>
        <div className="flex items-center gap-2">
          <Button type="button" size="sm" variant="ghost" onClick={autoDistribute}>
            Auto-distribute
          </Button>
        </div>
      </div>

      <div className="space-y-2">
        {parts.map((p, idx) => {
          const partErrors = errorsByPart[p.id] ?? [];
          const pctError = partErrors.find((e) => e.field === "percentage");
          const entityError = partErrors.find(
            (e) => e.field === "entity" || e.field === "category"
          );
          const childAmount = (absAmount * (Number.isFinite(p.percentage) ? p.percentage : 0)) / 100;
          return (
            <div
              key={p.id}
              className="grid gap-2 rounded-md border bg-background p-3 md:grid-cols-[80px_1fr_1fr_1fr_auto] items-start"
            >
              <div>
                <label
                  htmlFor={`split-pct-${p.id}`}
                  className="block section-label mb-1"
                >
                  Part {idx + 1}
                </label>
                <div className="relative">
                  <Input
                    id={`split-pct-${p.id}`}
                    type="number"
                    min={0}
                    max={100}
                    step="0.01"
                    value={Number.isFinite(p.percentage) ? p.percentage : 0}
                    onChange={(e) =>
                      updatePart(p.id, { percentage: Number(e.target.value) || 0 })
                    }
                    aria-invalid={pctError ? true : undefined}
                    aria-describedby={pctError ? `split-pct-err-${p.id}` : undefined}
                    className="pr-6 h-9 text-sm"
                  />
                  <span className="pointer-events-none absolute inset-y-0 right-2 flex items-center text-xs text-muted-foreground">
                    %
                  </span>
                </div>
                <div className="mt-1 text-[10px] tabular-nums text-muted-foreground">
                  {formatCurrency(childAmount)}
                </div>
              </div>
              <div>
                <label
                  htmlFor={`split-entity-${p.id}`}
                  className="block section-label mb-1"
                >
                  Entity
                </label>
                <select
                  id={`split-entity-${p.id}`}
                  value={p.entitySlug ?? ""}
                  onChange={(e) =>
                    updatePart(p.id, { entitySlug: e.target.value || undefined })
                  }
                  className="h-9 w-full rounded-md border border-input bg-background px-2 text-sm"
                  aria-invalid={entityError ? true : undefined}
                >
                  <option value="">&mdash;</option>
                  {ALL_ORGANIZATIONS.map((o) => (
                    <option key={o.slug} value={o.slug}>
                      {o.emoji ? `${o.emoji} ` : ""}
                      {o.name}
                    </option>
                  ))}
                </select>
              </div>
              <div>
                <label
                  htmlFor={`split-cat-${p.id}`}
                  className="block section-label mb-1"
                >
                  Category
                </label>
                <select
                  id={`split-cat-${p.id}`}
                  value={p.category ?? ""}
                  onChange={(e) =>
                    updatePart(p.id, { category: e.target.value || undefined })
                  }
                  className="h-9 w-full rounded-md border border-input bg-background px-2 text-sm"
                  aria-invalid={entityError ? true : undefined}
                >
                  <option value="">&mdash;</option>
                  {BILL_CATEGORIES.map((c) => (
                    <option key={c} value={c}>
                      {c}
                    </option>
                  ))}
                </select>
              </div>
              <div>
                <label
                  htmlFor={`split-note-${p.id}`}
                  className="block section-label mb-1"
                >
                  Note
                </label>
                <Input
                  id={`split-note-${p.id}`}
                  value={p.note ?? ""}
                  onChange={(e) =>
                    updatePart(p.id, { note: e.target.value || undefined })
                  }
                  placeholder="Optional"
                  className="h-9 text-sm"
                />
              </div>
              <div className="flex items-end h-full pb-0.5">
                <Button
                  type="button"
                  variant="ghost"
                  size="sm"
                  onClick={() => removePart(p.id)}
                  disabled={parts.length <= 1}
                  aria-label={`Remove part ${idx + 1}`}
                  title={parts.length <= 1 ? "At least one part required" : "Remove part"}
                >
                  &times;
                </Button>
              </div>
              {(pctError || entityError) && (
                <div className="md:col-span-5 text-[11px] text-destructive space-y-0.5">
                  {pctError && (
                    <p id={`split-pct-err-${p.id}`}>{pctError.message}</p>
                  )}
                  {entityError && <p>{entityError.message}</p>}
                </div>
              )}
            </div>
          );
        })}
      </div>

      <div className="mt-3 flex flex-wrap items-center gap-2">
        <Button type="button" size="sm" variant="outline" onClick={addPart}>
          + Add part
        </Button>
        <Badge
          variant={sumOk ? "success" : "destructive"}
          className="text-[11px]"
          aria-live="polite"
        >
          Sum: {sum.toFixed(2)}% {sumOk ? "OK" : "off"}
        </Badge>
        {globalErrors
          .filter((e) => (e.field as SplitErrorField) !== "percentage")
          .map((e, i) => (
            <span key={`ge-${i}`} className="text-[11px] text-destructive">
              {e.message}
            </span>
          ))}
        <div className="ml-auto flex items-center gap-2">
          <Button type="button" size="sm" variant="ghost" onClick={onCancel}>
            Cancel
          </Button>
          <Button
            type="button"
            size="sm"
            onClick={handleSave}
            disabled={!canSave}
            title={!canSave ? "Resolve validation errors before saving" : "Save split"}
          >
            Save split
          </Button>
        </div>
      </div>
    </div>
  );
}
