import * as React from "react";
import { Check, Search } from "lucide-react";
import { cn } from "@/lib/utils";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Slider } from "@/components/ui/slider";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";

/**
 * Form Primitives — WealthX DS (L3)
 *
 * Reusable input primitives for financial forms.
 * Used inside Opportunity edit modals and loan application forms.
 *
 * Components:
 * - CurrencyInputWithSlider  — formatted currency text input + range slider
 * - ConcernScale             — 1–5 priority/importance selector
 * - AddressAutocomplete      — text input with filtered suggestion dropdown
 * - OwnershipSplit           — two-owner percentage split (sums to 100 %)
 */

// ---------------------------------------------------------------------------
// CurrencyInputWithSlider
// ---------------------------------------------------------------------------

export interface CurrencyInputWithSliderProps {
  /** Numeric value in dollars */
  value?: number;
  /** Default value when uncontrolled */
  defaultValue?: number;
  min?: number;
  max?: number;
  step?: number;
  disabled?: boolean;
  /** Called with the updated numeric value */
  onValueChange?: (value: number) => void;
  className?: string;
}

function parseCurrencyToNumber(raw: string): number {
  const cleaned = raw.replace(/[^0-9.]/g, "");
  const n = parseFloat(cleaned);
  return isNaN(n) ? 0 : n;
}

function formatNumberToCurrency(n: number): string {
  return "$" + Math.round(n).toLocaleString("en-AU");
}

/**
 * Currency text input paired with a range slider.
 * The two controls stay in sync — editing the input moves the slider and vice versa.
 *
 * ```tsx
 * <CurrencyInputWithSlider
 *   value={loanAmount}
 *   min={100_000}
 *   max={3_000_000}
 *   step={10_000}
 *   onValueChange={setLoanAmount}
 * />
 * ```
 */
export function CurrencyInputWithSlider({
  value: controlledValue,
  defaultValue = 0,
  min = 0,
  max = 5_000_000,
  step = 10_000,
  disabled = false,
  onValueChange,
  className,
}: CurrencyInputWithSliderProps) {
  const [internalValue, setInternalValue] = React.useState(defaultValue);
  const numericValue =
    controlledValue !== undefined ? controlledValue : internalValue;

  const [inputText, setInputText] = React.useState(
    formatNumberToCurrency(numericValue),
  );
  const [isFocused, setIsFocused] = React.useState(false);

  // Sync inputText when controlled value changes externally
  React.useEffect(() => {
    if (!isFocused) {
      setInputText(formatNumberToCurrency(numericValue));
    }
  }, [numericValue, isFocused]);

  const commitValue = (n: number) => {
    const clamped = Math.max(min, Math.min(max, n));
    if (controlledValue === undefined) setInternalValue(clamped);
    onValueChange?.(clamped);
    setInputText(formatNumberToCurrency(clamped));
  };

  return (
    <div className={cn("flex flex-col gap-3", className)}>
      {/* Text input */}
      <Input
        type="text"
        value={isFocused ? inputText : formatNumberToCurrency(numericValue)}
        disabled={disabled}
        onFocus={() => {
          setIsFocused(true);
          setInputText(formatNumberToCurrency(numericValue));
        }}
        onChange={(e) => setInputText(e.target.value)}
        onBlur={() => {
          setIsFocused(false);
          commitValue(parseCurrencyToNumber(inputText));
        }}
        onKeyDown={(e) => {
          if (e.key === "Enter") {
            (e.target as HTMLInputElement).blur();
          }
        }}
        className="tabular-nums"
        aria-label="Currency amount"
      />

      {/* Slider */}
      <Slider
        value={numericValue}
        min={min}
        max={max}
        step={step}
        disabled={disabled}
        onValueChange={(n) => {
          if (controlledValue === undefined) setInternalValue(n);
          onValueChange?.(n);
        }}
      />
    </div>
  );
}

// ---------------------------------------------------------------------------
// ConcernScale
// ---------------------------------------------------------------------------

const CONCERN_LABELS: Record<number, string> = {
  1: "Not important",
  2: "Slightly important",
  3: "Moderately important",
  4: "Very important",
  5: "Critical",
};

export interface ConcernScaleProps {
  value?: number;
  defaultValue?: number;
  disabled?: boolean;
  /** Number of steps (default 5) */
  steps?: number;
  lowLabel?: string;
  highLabel?: string;
  onValueChange?: (value: number) => void;
  className?: string;
}

/**
 * 1–N priority / importance selector using DS ToggleGroup buttons.
 * One button is active at a time; selecting the same value again clears to 0.
 *
 * ```tsx
 * <ConcernScale value={priority} onValueChange={setPriority} />
 * ```
 */
export function ConcernScale({
  value: controlledValue,
  defaultValue = 0,
  disabled = false,
  steps = 5,
  lowLabel = "Not important",
  highLabel = "Critical",
  onValueChange,
  className,
}: ConcernScaleProps) {
  const [internalValue, setInternalValue] = React.useState(defaultValue);
  const selected =
    controlledValue !== undefined ? controlledValue : internalValue;

  const handleValueChange = (val: string[]) => {
    const n = val[0] ? Number(val[0]) : 0;
    if (controlledValue === undefined) setInternalValue(n);
    onValueChange?.(n);
  };

  return (
    <div className={cn("flex flex-col gap-2", className)}>
      <ToggleGroup
        type="single"
        value={selected > 0 ? [String(selected)] : []}
        onValueChange={handleValueChange}
        variant="outline"
        size="sm"
        disabled={disabled}
        className="w-full"
      >
        {Array.from({ length: steps }, (_, i) => i + 1).map((n) => (
          <ToggleGroupItem
            key={n}
            value={String(n)}
            aria-label={CONCERN_LABELS[n] ?? String(n)}
            className="flex-1"
          >
            {n}
          </ToggleGroupItem>
        ))}
      </ToggleGroup>

      {/* Extreme labels */}
      <div className="flex justify-between text-caption text-muted-foreground">
        <span>{lowLabel}</span>
        <span>{highLabel}</span>
      </div>

      {/* Selected label */}
      {selected > 0 && (
        <p className="text-caption text-foreground">
          {CONCERN_LABELS[selected] ?? `Level ${selected}`}
        </p>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// AddressAutocomplete
// ---------------------------------------------------------------------------

export interface AddressOption {
  id: string;
  label: string;
  suburb?: string;
  state?: string;
  postcode?: string;
}

export interface AddressAutocompleteProps {
  value?: string;
  placeholder?: string;
  suggestions?: AddressOption[];
  disabled?: boolean;
  onValueChange?: (value: string) => void;
  onSelect?: (option: AddressOption) => void;
  className?: string;
}

const DEFAULT_SUGGESTIONS: AddressOption[] = [
  {
    id: "1",
    label: "12 Harbour View Terrace, Mosman NSW 2088",
    suburb: "Mosman",
    state: "NSW",
    postcode: "2088",
  },
  {
    id: "2",
    label: "5 Coastal Road, Manly NSW 2095",
    suburb: "Manly",
    state: "NSW",
    postcode: "2095",
  },
  {
    id: "3",
    label: "24 Collins Street, Melbourne VIC 3000",
    suburb: "Melbourne",
    state: "VIC",
    postcode: "3000",
  },
  {
    id: "4",
    label: "88 Pacific Highway, St Leonards NSW 2065",
    suburb: "St Leonards",
    state: "NSW",
    postcode: "2065",
  },
  {
    id: "5",
    label: "1 Queen Street, Brisbane QLD 4000",
    suburb: "Brisbane",
    state: "QLD",
    postcode: "4000",
  },
];

/**
 * Address text input with filtered suggestion dropdown.
 * Filters the `suggestions` list on each keystroke (case-insensitive substring match).
 * Pass `onSelect` to receive the full structured `AddressOption` on selection.
 *
 * In production, replace `suggestions` with results from a geocoding API.
 *
 * ```tsx
 * <AddressAutocomplete
 *   value={address}
 *   onValueChange={setAddress}
 *   onSelect={(opt) => console.log(opt.postcode)}
 * />
 * ```
 */
export function AddressAutocomplete({
  value: controlledValue,
  placeholder = "Start typing an address…",
  suggestions = DEFAULT_SUGGESTIONS,
  disabled = false,
  onValueChange,
  onSelect,
  className,
}: AddressAutocompleteProps) {
  const [internalValue, setInternalValue] = React.useState("");
  const inputValue =
    controlledValue !== undefined ? controlledValue : internalValue;

  const [open, setOpen] = React.useState(false);
  const [activeIndex, setActiveIndex] = React.useState(-1);
  const containerRef = React.useRef<HTMLDivElement>(null);
  const listRef = React.useRef<HTMLUListElement>(null);

  const filtered = React.useMemo(() => {
    if (!inputValue.trim()) return suggestions.slice(0, 5);
    const q = inputValue.toLowerCase();
    return suggestions
      .filter((s) => s.label.toLowerCase().includes(q))
      .slice(0, 5);
  }, [inputValue, suggestions]);

  const setValue = (v: string) => {
    if (controlledValue === undefined) setInternalValue(v);
    onValueChange?.(v);
  };

  const handleSelect = (opt: AddressOption) => {
    setValue(opt.label);
    onSelect?.(opt);
    setOpen(false);
    setActiveIndex(-1);
  };

  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (!open) return;
    if (e.key === "ArrowDown") {
      e.preventDefault();
      setActiveIndex((i) => Math.min(i + 1, filtered.length - 1));
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      setActiveIndex((i) => Math.max(i - 1, -1));
    } else if (e.key === "Enter" && activeIndex >= 0) {
      e.preventDefault();
      handleSelect(filtered[activeIndex]);
    } else if (e.key === "Escape") {
      setOpen(false);
    }
  };

  // Close on outside click
  React.useEffect(() => {
    const handler = (e: MouseEvent) => {
      if (
        containerRef.current &&
        !containerRef.current.contains(e.target as Node)
      ) {
        setOpen(false);
      }
    };
    document.addEventListener("mousedown", handler);
    return () => document.removeEventListener("mousedown", handler);
  }, []);

  return (
    <div ref={containerRef} className={cn("relative", className)}>
      <div className="relative">
        <Search className="absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-muted-foreground pointer-events-none" />
        <Input
          type="text"
          value={inputValue}
          placeholder={placeholder}
          disabled={disabled}
          className="pl-8"
          onChange={(e) => {
            setValue(e.target.value);
            setOpen(true);
            setActiveIndex(-1);
          }}
          onFocus={() => setOpen(true)}
          onKeyDown={handleKeyDown}
          aria-autocomplete="list"
          aria-expanded={open}
        />
      </div>

      {open && filtered.length > 0 && (
        <ul
          ref={listRef}
          role="listbox"
          className={cn(
            "absolute z-50 top-full left-0 right-0 mt-1",
            "border border-border bg-popover shadow-md",
            "max-h-48 overflow-y-auto py-1",
          )}
        >
          {filtered.map((opt, idx) => (
            <li
              key={opt.id}
              role="option"
              aria-selected={idx === activeIndex}
              onMouseEnter={() => setActiveIndex(idx)}
              onMouseDown={(e) => {
                e.preventDefault();
                handleSelect(opt);
              }}
              className={cn(
                "flex items-center gap-2 px-3 py-2 text-body-small cursor-pointer",
                idx === activeIndex
                  ? "bg-accent text-accent-foreground"
                  : "hover:bg-accent/50",
              )}
            >
              <span className="flex-1 truncate">{opt.label}</span>
              {idx === activeIndex && (
                <Check className="h-3.5 w-3.5 shrink-0 text-primary" />
              )}
            </li>
          ))}
        </ul>
      )}
    </div>
  );
}

// ---------------------------------------------------------------------------
// OwnershipSplit
// ---------------------------------------------------------------------------

export interface OwnershipOwner {
  id: string;
  name: string;
  /** Percentage 0–100 */
  share: number;
}

export interface OwnershipSplitProps {
  owners?: OwnershipOwner[];
  disabled?: boolean;
  onOwnersChange?: (owners: OwnershipOwner[]) => void;
  className?: string;
}

const DEFAULT_OWNERS: OwnershipOwner[] = [
  { id: "main", name: "Main Applicant", share: 50 },
  { id: "co", name: "Co-Applicant", share: 50 },
];

/**
 * Two-owner (or N-owner) percentage split control.
 * Adjusting one owner's slider redistributes the remainder proportionally.
 * The sum always stays at 100 %.
 *
 * ```tsx
 * <OwnershipSplit
 *   owners={[
 *     { id: "main", name: "James Harbour", share: 60 },
 *     { id: "co",   name: "Sarah Harbour", share: 40 },
 *   ]}
 *   onOwnersChange={setOwners}
 * />
 * ```
 */
export function OwnershipSplit({
  owners: controlledOwners,
  disabled = false,
  onOwnersChange,
  className,
}: OwnershipSplitProps) {
  const [internalOwners, setInternalOwners] =
    React.useState<OwnershipOwner[]>(DEFAULT_OWNERS);

  const owners =
    controlledOwners !== undefined ? controlledOwners : internalOwners;

  const setOwners = (updated: OwnershipOwner[]) => {
    if (controlledOwners === undefined) setInternalOwners(updated);
    onOwnersChange?.(updated);
  };

  const handleSliderChange = (id: string, newShare: number) => {
    if (owners.length !== 2) return; // Only 2-owner redistribution implemented
    const clamped = Math.max(0, Math.min(100, Math.round(newShare)));
    const other = owners.find((o) => o.id !== id);
    if (!other) return;
    setOwners(
      owners.map((o) =>
        o.id === id ? { ...o, share: clamped } : { ...o, share: 100 - clamped },
      ),
    );
  };

  const handleInputChange = (id: string, raw: string) => {
    const n = parseInt(raw.replace(/[^0-9]/g, ""), 10);
    if (isNaN(n)) return;
    handleSliderChange(id, n);
  };

  return (
    <div className={cn("flex gap-4", className)}>
      {owners.map((owner) => {
        const pct = Math.max(0, Math.min(100, owner.share));
        return (
          <div key={owner.id} className="flex flex-col gap-2 flex-1">
            <div className="flex items-center justify-between">
              <Label className="text-label-small">{owner.name}</Label>
              <Input
                type="text"
                value={`${pct}%`}
                disabled={disabled}
                className="w-14 h-7 text-label-small text-right tabular-nums px-2"
                onChange={(e) => handleInputChange(owner.id, e.target.value)}
                onBlur={(e) => handleInputChange(owner.id, e.target.value)}
              />
            </div>
            <Slider
              value={pct}
              min={0}
              max={100}
              step={1}
              disabled={disabled}
              onValueChange={(n) => handleSliderChange(owner.id, n)}
            />
          </div>
        );
      })}
    </div>
  );
}
