import { useEffect, useMemo, useState } from "react";
import { format, parseISO, subDays } from "date-fns";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { DatePicker } from "@/components/ui/date-picker";
import {
  Dialog,
  DialogContent,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Field, FieldLabel } from "@/components/ui/field";
import { Input } from "@/components/ui/input";
import { PaginationNavButtons } from "@/components/ui/pagination";
import { Spinner } from "@/components/ui/spinner";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";

/**
 * BankStatementGenerateDialog — WealthX DS (L4 Template)
 *
 * Dialog for generating a new bank statement PDF from connected bank accounts.
 * Shown when the user clicks "Generate" in the Bank Statement tab of
 * `OpportunityDetailsDrawer`.
 *
 * Internal state:
 *   - Statement name (Input)
 *   - Range preset: 90 / 180 / 365 days or Custom (ToggleGroup + DatePickers)
 *   - Applicant type: primary / secondary (ToggleGroup, matching Statement period)
 *   - Selected bank account IDs (Table with Checkboxes, paginated at 5/page)
 *
 * Data handed in via props (consumer owns fetching):
 *   - `bankAccounts` — pre-filtered for the current `applicantType`
 *   - `isLoadingAccounts` — spinner while the consumer re-fetches after type change
 *
 * Layer: L4 Template
 *
 * Data source: `useAggregatedBankAccounts` in backoffice (not included here)
 */

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

export type BankStatementRangePreset = 90 | 180 | 365 | "custom";

export interface BankStatementAccount {
  id: string;
  /** Display name for the account (e.g. "Everyday Savings"). */
  name: string;
  /** BSB / account number string. */
  accountNo?: string;
  /** Bank / institution name. */
  institutionName?: string;
  /** URL to institution logo image. */
  institutionLogo?: string;
  /** ISO date string of when the account was last synced. */
  lastUpdated?: string;
}

export interface BankStatementGeneratePayload {
  statementName: string;
  rangePreset: BankStatementRangePreset;
  /** ISO date string (YYYY-MM-DD). Set for all presets as well as custom. */
  fromDate: string;
  /** ISO date string (YYYY-MM-DD). Set for all presets as well as custom. */
  toDate: string;
  applicantType: "primary" | "secondary";
  selectedAccountIds: string[];
}

export interface BankStatementGenerateDialogProps {
  open: boolean;
  onClose: () => void;
  /**
   * Called when the user clicks Generate (only if form is valid).
   * Consumer is responsible for the actual API call.
   */
  onSubmit: (payload: BankStatementGeneratePayload) => void;
  /**
   * Called when the user changes the applicant type so the consumer can
   * re-fetch / re-filter bank accounts for the new type.
   */
  onApplicantTypeChange?: (type: "primary" | "secondary") => void;
  /**
   * Bank accounts pre-filtered for the currently selected applicant type.
   * Pass an empty array while loading.
   */
  bankAccounts: BankStatementAccount[];
  /** Enable the "Co-applicant" option. When false it renders disabled, not hidden. */
  hasCoApplicant?: boolean;
  /** Show a loading spinner in the accounts table while the consumer re-fetches. */
  isLoadingAccounts?: boolean;
  /** Show a loading indicator on the Generate button while the API call is in flight. */
  isLoading?: boolean;
  className?: string;
}

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------

const APPLICANT_TYPE_LABELS: Record<"primary" | "secondary", string> = {
  primary: "Main applicant",
  secondary: "Co-applicant",
};

const ACCOUNTS_PAGE_SIZE = 5;

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function toIsoDate(date: Date): string {
  return date.toISOString().slice(0, 10);
}

function presetToDateRange(preset: number): { from: string; to: string } {
  const today = new Date();
  return {
    from: toIsoDate(subDays(today, preset - 1)),
    to: toIsoDate(today),
  };
}

// ---------------------------------------------------------------------------
// BankStatementGenerateDialog
// ---------------------------------------------------------------------------

export function BankStatementGenerateDialog({
  open,
  onClose,
  onSubmit,
  onApplicantTypeChange,
  bankAccounts,
  hasCoApplicant = false,
  isLoadingAccounts = false,
  isLoading = false,
  className,
}: BankStatementGenerateDialogProps) {
  const [statementName, setStatementName] = useState("Bank Statement 1");
  const [rangePreset, setRangePreset] = useState<BankStatementRangePreset>(90);
  // Initialise immediately so the Period column never shows "—" on first open.
  const [fromDate, setFromDate] = useState<string>(
    () => presetToDateRange(90).from,
  );
  const [toDate, setToDate] = useState<string>(() => presetToDateRange(90).to);
  const [applicantType, setApplicantType] = useState<
    "primary" | "secondary" | ""
  >("");
  const [selectedAccountIds, setSelectedAccountIds] = useState<string[]>([]);
  const [accountPage, setAccountPage] = useState(1);

  // Reset form whenever the dialog opens.
  useEffect(() => {
    if (!open) return;
    const timer = setTimeout(() => {
      const { from, to } = presetToDateRange(90);
      setStatementName("Bank Statement 1");
      setRangePreset(90);
      setFromDate(from);
      setToDate(to);
      setApplicantType("");
      setSelectedAccountIds([]);
      setAccountPage(1);
    }, 0);
    return () => clearTimeout(timer);
  }, [open]);

  // ── Applicant type ───────────────────────────────────────────────────────

  const handleApplicantTypeChange = (type: "primary" | "secondary") => {
    setApplicantType(type);
    setSelectedAccountIds([]);
    setAccountPage(1);
    onApplicantTypeChange?.(type);
  };

  // ToggleGroup emits an empty array when the active item is clicked again;
  // the applicant is not an optional choice, so that deselect is ignored.
  const handleApplicantChange = (val: string[]) => {
    if (val.length === 0) return;
    handleApplicantTypeChange(val[0] as "primary" | "secondary");
  };

  // ── Date range preset ────────────────────────────────────────────────────

  const handlePresetChange = (val: string[]) => {
    if (val.length === 0) return;
    const raw = val[0];
    const preset: BankStatementRangePreset =
      raw === "custom" ? "custom" : (Number(raw) as 90 | 180 | 365);
    setRangePreset(preset);
    if (preset !== "custom") {
      const { from, to } = presetToDateRange(preset);
      setFromDate(from);
      setToDate(to);
    }
  };

  // ── Account selection ────────────────────────────────────────────────────

  const areAllSelected =
    bankAccounts.length > 0 &&
    selectedAccountIds.length === bankAccounts.length;
  const isSomeSelected = selectedAccountIds.length > 0 && !areAllSelected;

  const handleToggleAccount = (id: string) => {
    setSelectedAccountIds((prev) =>
      prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id],
    );
  };

  const handleToggleAll = () => {
    setSelectedAccountIds(areAllSelected ? [] : bankAccounts.map((a) => a.id));
  };

  // ── Accounts pagination ──────────────────────────────────────────────────

  const accountPageCount = Math.ceil(bankAccounts.length / ACCOUNTS_PAGE_SIZE);
  const pagedAccounts = bankAccounts.slice(
    (accountPage - 1) * ACCOUNTS_PAGE_SIZE,
    accountPage * ACCOUNTS_PAGE_SIZE,
  );

  // ── Period label for the accounts table ─────────────────────────────────

  const periodLabel = useMemo(() => {
    if (fromDate && toDate) {
      return `${format(parseISO(fromDate), "dd MMM yyyy")} – ${format(parseISO(toDate), "dd MMM yyyy")}`;
    }
    return "—";
  }, [fromDate, toDate]);

  // ── Submit guard ─────────────────────────────────────────────────────────

  const isSubmitDisabled =
    !statementName.trim() ||
    !applicantType ||
    (rangePreset === "custom" && (!fromDate || !toDate)) ||
    selectedAccountIds.length === 0;

  const handleSubmit = () => {
    if (isSubmitDisabled || !applicantType) return;
    onSubmit({
      statementName,
      rangePreset,
      fromDate,
      toDate,
      applicantType,
      selectedAccountIds,
    });
  };

  // ── Render ───────────────────────────────────────────────────────────────

  return (
    <Dialog open={open} onOpenChange={(o) => !o && onClose()}>
      <DialogContent
        size="3xl"
        className={className}
        data-slot="bank-statement-generate-dialog"
      >
        <DialogHeader>
          <DialogTitle>Generate Bank Statement</DialogTitle>
        </DialogHeader>

        <div className="flex flex-col gap-4">
          {/* Statement name */}
          <Field>
            <FieldLabel>Name</FieldLabel>
            <Input
              value={statementName}
              onChange={(e) => setStatementName(e.target.value)}
              placeholder="Bank Statement 1"
            />
          </Field>

          {/* Date range preset */}
          <div className="flex flex-col gap-2">
            <span className="text-body-small text-muted-foreground">
              Statement period
            </span>
            <ToggleGroup
              type="single"
              variant="outline"
              value={[String(rangePreset)]}
              onValueChange={handlePresetChange}
              className="w-full"
            >
              <ToggleGroupItem value="90" className="flex-1">
                3 Months
              </ToggleGroupItem>
              <ToggleGroupItem value="180" className="flex-1">
                6 Months
              </ToggleGroupItem>
              <ToggleGroupItem value="365" className="flex-1">
                12 Months
              </ToggleGroupItem>
              <ToggleGroupItem value="custom" className="flex-1">
                Custom
              </ToggleGroupItem>
            </ToggleGroup>
          </div>

          {/* Custom date pickers */}
          {rangePreset === "custom" && (
            <div className="flex gap-3">
              <DatePicker
                value={fromDate ? parseISO(fromDate) : undefined}
                onChange={(date) => setFromDate(date ? toIsoDate(date) : "")}
                placeholder="From Date"
                className="flex-1"
              />
              <DatePicker
                value={toDate ? parseISO(toDate) : undefined}
                onChange={(date) => setToDate(date ? toIsoDate(date) : "")}
                placeholder="To Date"
                className="flex-1"
              />
            </div>
          )}

          {/* Applicant type */}
          <div className="flex flex-col gap-2">
            <span className="text-body-small text-muted-foreground">
              Statement for
            </span>
            <ToggleGroup
              type="single"
              variant="outline"
              value={applicantType ? [applicantType] : []}
              onValueChange={handleApplicantChange}
              className="w-full"
            >
              <ToggleGroupItem value="primary" className="flex-1">
                {APPLICANT_TYPE_LABELS.primary}
              </ToggleGroupItem>
              <ToggleGroupItem
                value="secondary"
                className="flex-1"
                disabled={!hasCoApplicant}
                title={
                  hasCoApplicant
                    ? undefined
                    : "This scenario has no co-applicant"
                }
              >
                {APPLICANT_TYPE_LABELS.secondary}
              </ToggleGroupItem>
            </ToggleGroup>
          </div>

          {/* Bank accounts table */}
          {applicantType && (
            <div className="mt-1">
              {isLoadingAccounts ? (
                <div className="flex items-center justify-center p-6">
                  <Spinner size="lg" />
                </div>
              ) : bankAccounts.length === 0 ? (
                <p className="py-4 text-center text-body-medium text-muted-foreground">
                  No bank accounts found for the selected applicant
                </p>
              ) : (
                <>
                  <Table className="table-fixed">
                    <TableHeader>
                      <TableRow>
                        <TableHead className="w-10">
                          <Checkbox
                            checked={areAllSelected}
                            indeterminate={isSomeSelected}
                            onCheckedChange={handleToggleAll}
                            aria-label="Select all accounts"
                          />
                        </TableHead>
                        <TableHead>Account Name</TableHead>
                        <TableHead className="w-40">Account Number</TableHead>
                        <TableHead className="w-52">Period</TableHead>
                        <TableHead className="w-28">Last Updated</TableHead>
                      </TableRow>
                    </TableHeader>
                    <TableBody>
                      {pagedAccounts.map((account) => {
                        const isSelected = selectedAccountIds.includes(
                          account.id,
                        );
                        return (
                          <TableRow
                            key={account.id}
                            data-state={isSelected ? "selected" : undefined}
                          >
                            <TableCell>
                              <Checkbox
                                checked={isSelected}
                                onCheckedChange={() =>
                                  handleToggleAccount(account.id)
                                }
                                aria-label={`Select ${account.name}`}
                              />
                            </TableCell>
                            <TableCell>
                              <div className="flex min-w-0 items-center gap-2">
                                {account.institutionLogo && (
                                  <img
                                    src={account.institutionLogo}
                                    alt={account.institutionName ?? ""}
                                    className="size-8 shrink-0 object-cover"
                                  />
                                )}
                                <span className="truncate text-body-medium font-semibold">
                                  {account.name ||
                                    account.institutionName ||
                                    "—"}
                                </span>
                              </div>
                            </TableCell>
                            <TableCell>
                              <span className="truncate text-body-medium">
                                {account.accountNo ?? "—"}
                              </span>
                            </TableCell>
                            <TableCell>
                              <span className="truncate text-body-medium">
                                {periodLabel}
                              </span>
                            </TableCell>
                            <TableCell>
                              <span className="truncate text-body-medium">
                                {account.lastUpdated
                                  ? format(
                                      parseISO(account.lastUpdated),
                                      "dd MMM yyyy",
                                    )
                                  : "—"}
                              </span>
                            </TableCell>
                          </TableRow>
                        );
                      })}
                    </TableBody>
                  </Table>
                  {accountPageCount > 1 && (
                    <div className="flex items-center justify-between pt-2">
                      <span className="text-body-small text-muted-foreground">
                        {(accountPage - 1) * ACCOUNTS_PAGE_SIZE + 1}–
                        {Math.min(
                          accountPage * ACCOUNTS_PAGE_SIZE,
                          bankAccounts.length,
                        )}{" "}
                        of {bankAccounts.length} accounts
                      </span>
                      <PaginationNavButtons
                        hasPrev={accountPage > 1}
                        hasNext={accountPage < accountPageCount}
                        onFirst={() => setAccountPage(1)}
                        onPrev={() => setAccountPage((p) => p - 1)}
                        onNext={() => setAccountPage((p) => p + 1)}
                        onLast={() => setAccountPage(accountPageCount)}
                      />
                    </div>
                  )}
                </>
              )}
            </div>
          )}
        </div>

        <DialogFooter>
          <Button variant="ghost" onClick={onClose}>
            Cancel
          </Button>
          <Button
            onClick={handleSubmit}
            disabled={isSubmitDisabled}
            loading={isLoading}
          >
            Generate
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
