import { useCallback, useEffect, useMemo, useState } from "react";
import { Trash2, Plus } from "lucide-react";
import { cn } from "@/lib/utils";
import { formatCurrency } from "@/lib/format-currency";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import {
  Dialog,
  DialogContent,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Field, FieldLabel } from "@/components/ui/field";
import {
  AddressAutocomplete,
  type AddressOption,
} from "@/components/ui/form-primitives";
import { Input } from "@/components/ui/input";
import { Separator } from "@/components/ui/separator";
import { Spinner } from "@/components/ui/spinner";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";

/**
 * PropertyReportDialog — WealthX DS (L4 Template)
 *
 * Dialog for generating a property valuation report from the scenario's
 * linked properties. Opened from the Bank Statement tab of
 * `OpportunityDetailsDrawer` when the user selects "Property Report" and
 * clicks "Generate".
 *
 * Internal state:
 *   - Report name (Input)
 *   - Manually added properties (via AddressAutocomplete + Add button)
 *   - Selected property IDs (Table with Checkboxes)
 *
 * Data handed in via props (consumer owns fetching):
 *   - `properties` — pre-loaded properties from the scenario (API list)
 *   - `isLoadingProperties` — spinner while fetching
 *   - `searchResults` — address search results driven by `onSearchQueryChange`
 *
 * Layer: L4 Template
 */

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

export interface PropertyItem {
  id: string;
  address?: string;
  propertyType?: string;
  /** Estimated value in dollars. */
  estimateValue?: number;
}

export interface PropertySearchResult {
  /** Unique property identifier returned by the address search service. */
  id: string;
  /** Full address string shown in the dropdown. */
  address: string;
}

export interface PropertyReportPayload {
  reportName: string;
  selectedPropertyIds: string[];
}

export interface PropertyReportDialogProps {
  open: boolean;
  onClose: () => void;
  /**
   * Called when the user clicks Generate (only when form is valid).
   * Consumer is responsible for the actual API call.
   */
  onSubmit: (payload: PropertyReportPayload) => void;
  /** Pre-loaded properties from the scenario's loan data. */
  properties: PropertyItem[];
  /** Provide `true` while the consumer is fetching the scenario's properties. */
  isLoadingProperties?: boolean;
  /**
   * Address search results for the autocomplete dropdown.
   * Consumer debounces and fetches when `onSearchQueryChange` fires.
   */
  searchResults?: PropertySearchResult[];
  /**
   * Called when the user types in the address search input (debounce externally).
   * Pass an empty string when the query is cleared.
   */
  onSearchQueryChange?: (query: string) => void;
  /** Show a loading indicator on the Generate button while the API call is in flight. */
  isLoading?: boolean;
  className?: string;
}

// ---------------------------------------------------------------------------
// PropertyReportDialog
// ---------------------------------------------------------------------------

export function PropertyReportDialog({
  open,
  onClose,
  onSubmit,
  properties,
  isLoadingProperties = false,
  searchResults = [],
  onSearchQueryChange,
  isLoading = false,
  className,
}: PropertyReportDialogProps) {
  const [reportName, setReportName] = useState("Property Report 1");
  const [selectedPropertyIds, setSelectedPropertyIds] = useState<string[]>([]);

  // Properties added manually via the address search (not in the API list)
  const [manualProperties, setManualProperties] = useState<PropertyItem[]>([]);

  // Address autocomplete state
  const [addressInputValue, setAddressInputValue] = useState("");
  const [selectedSuggestion, setSelectedSuggestion] =
    useState<PropertySearchResult | null>(null);

  // Convert searchResults → AddressOption[] for AddressAutocomplete
  const addressOptions = useMemo<AddressOption[]>(
    () => searchResults.map((r) => ({ id: r.id, label: r.address })),
    [searchResults],
  );

  // Reset form whenever the dialog opens
  useEffect(() => {
    if (!open) return;
    setReportName("Property Report 1");
    setSelectedPropertyIds([]);
    setManualProperties([]);
    setAddressInputValue("");
    setSelectedSuggestion(null);
    onSearchQueryChange?.("");
  }, [open]); // eslint-disable-line react-hooks/exhaustive-deps

  // Combined list shown in the table
  const allProperties = useMemo<PropertyItem[]>(
    () => [...properties, ...manualProperties],
    [properties, manualProperties],
  );

  // ── Property selection ───────────────────────────────────────────────────

  const areAllSelected =
    allProperties.length > 0 &&
    selectedPropertyIds.length === allProperties.length;
  const isSomeSelected = selectedPropertyIds.length > 0 && !areAllSelected;

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

  const handleToggleAll = () => {
    if (areAllSelected) {
      setSelectedPropertyIds([]);
    } else {
      setSelectedPropertyIds(allProperties.map((p) => p.id));
    }
  };

  // ── Address search & manual add ──────────────────────────────────────────

  const handleAddProperty = useCallback(() => {
    if (!selectedSuggestion) return;
    const { id, address } = selectedSuggestion;

    const alreadyExists = allProperties.some((p) => p.id === id);
    if (alreadyExists) return; // silently skip (button is disabled when already added)

    setManualProperties((prev) => [...prev, { id, address }]);
    setSelectedSuggestion(null);
    setAddressInputValue("");
    onSearchQueryChange?.("");
  }, [selectedSuggestion, allProperties, onSearchQueryChange]);

  const handleRemoveManual = useCallback((id: string) => {
    setManualProperties((prev) => prev.filter((p) => p.id !== id));
    setSelectedPropertyIds((prev) => prev.filter((x) => x !== id));
  }, []);

  const isManual = (id: string) => manualProperties.some((p) => p.id === id);

  const isAddDisabled =
    !selectedSuggestion ||
    allProperties.some((p) => p.id === selectedSuggestion.id);

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

  const isSubmitDisabled =
    !reportName.trim() || selectedPropertyIds.length === 0;

  const handleSubmit = () => {
    if (isSubmitDisabled) return;
    onSubmit({ reportName, selectedPropertyIds });
  };

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

  return (
    <Dialog open={open} onOpenChange={(o) => !o && onClose()}>
      <DialogContent
        size="auto"
        className={cn(className)}
        data-slot="property-report-dialog"
      >
        <DialogHeader>
          <DialogTitle>Property Report</DialogTitle>
        </DialogHeader>

        <Separator />

        <div className="flex flex-col gap-4 pt-1">
          {/* Report name */}
          <Field>
            <FieldLabel>Name</FieldLabel>
            <Input
              value={reportName}
              onChange={(e) => setReportName(e.target.value)}
              placeholder="Property Report 1"
            />
          </Field>

          {/* Address search + Add button */}
          <div className="flex items-end gap-2">
            <Field className="flex-1">
              <FieldLabel>Search property</FieldLabel>
              <AddressAutocomplete
                value={addressInputValue}
                suggestions={addressOptions}
                placeholder="Start typing an address…"
                onValueChange={(v) => {
                  setAddressInputValue(v);
                  setSelectedSuggestion(null);
                  onSearchQueryChange?.(v);
                }}
                onSelect={(opt) => {
                  setSelectedSuggestion({ id: opt.id, address: opt.label });
                }}
              />
            </Field>
            <Button
              variant="outline"
              onClick={handleAddProperty}
              disabled={isAddDisabled}
            >
              <Plus className="size-4" />
              Add
            </Button>
          </div>

          {/* Properties table */}
          <div>
            {isLoadingProperties ? (
              <div className="flex items-center justify-center p-6">
                <Spinner size="lg" />
              </div>
            ) : allProperties.length === 0 ? (
              <p className="py-4 text-center text-body-medium text-muted-foreground">
                No properties found. Use the search above to add properties.
              </p>
            ) : (
              <Table>
                <TableHeader>
                  <TableRow>
                    <TableHead className="w-10">
                      <Checkbox
                        checked={areAllSelected}
                        indeterminate={isSomeSelected}
                        onCheckedChange={handleToggleAll}
                        aria-label="Select all properties"
                      />
                    </TableHead>
                    <TableHead>Address</TableHead>
                    <TableHead>Property Type</TableHead>
                    <TableHead>Estimate</TableHead>
                    <TableHead className="w-10" />
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {allProperties.map((property) => (
                    <TableRow key={property.id}>
                      <TableCell>
                        <Checkbox
                          checked={selectedPropertyIds.includes(property.id)}
                          onCheckedChange={() =>
                            handleToggleProperty(property.id)
                          }
                          aria-label={`Select ${property.address ?? property.id}`}
                        />
                      </TableCell>
                      <TableCell>
                        <span className="text-body-medium font-semibold">
                          {property.address ?? "—"}
                        </span>
                      </TableCell>
                      <TableCell>
                        <span className="text-body-medium">
                          {property.propertyType ?? "—"}
                        </span>
                      </TableCell>
                      <TableCell>
                        <span className="text-body-medium">
                          {property.estimateValue
                            ? formatCurrency(property.estimateValue)
                            : "—"}
                        </span>
                      </TableCell>
                      <TableCell>
                        {isManual(property.id) && (
                          <Button
                            variant="ghost"
                            size="icon-sm"
                            aria-label="Remove property"
                            onClick={() => handleRemoveManual(property.id)}
                          >
                            <Trash2 className="size-4" />
                          </Button>
                        )}
                      </TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            )}
          </div>
        </div>

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