'use client';

/**
 * ShippingAddressPicker — address picker + per-vendor shipping cost summary.
 *
 * Rendered inside CheckoutModal for ITEM-type deals with delivery fulfillment.
 * Fetches saved addresses, lets the user pick one, and shows per-vendor
 * shipping quotes fetched from POST /api/checkout/shipping-quote.
 */

import { useState, useEffect, useCallback, type SubmitEvent } from 'react';
import { Pencil, Trash2 } from 'lucide-react';
import { useT } from '@/lib/i18n/react';
import { Card } from '@/components/ui/layout/Card';
import { Button } from '@/components/ui/primitives/Button';
import { IconButton } from '@/components/ui/primitives/IconButton';
import { Input } from '@/components/ui/primitives/Input';
import { Label } from '@/components/ui/primitives/Label';
import { RadioGroup, RadioItem } from '@/components/ui/primitives/RadioGroup';
import {
  Dialog,
  DialogTrigger,
  DialogContent,
  DialogTitle,
  DialogDescription,
} from '@/components/ui/overlays/Dialog';
import {
  AlertDialog,
  AlertDialogContent,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogCancel,
  AlertDialogAction,
} from '@/components/ui/overlays/AlertDialog';
import { Spinner } from '@/components/ui/feedback/Spinner';
import { InlineNotice } from '@/components/ui/feedback/InlineNotice';
import { formatAgorotShekels } from '@/lib/money';
import { captureCaught } from '@/lib/observability';
import { normalizeIlPhone } from '@/lib/validation/shipping';
import { formatIsraeliAddress } from '@/lib/address';

// ─── Types ────────────────────────────────────────────────────────────────────

export interface ShippingAddress {
  id: string;
  recipientName: string;
  recipientPhone: string;
  cityCode: string;
  cityName: string;
  streetCode?: string | null;
  streetName: string;
  houseNumber: string;
  apt?: string | null;
  entrance?: string | null;
  floor?: string | null;
  zip?: string | null;
  zipValidated?: boolean;
  notes?: string | null;
  isDefault: boolean;
}

export interface ShippingQuote {
  dealId: string;
  vendorName: string;
  costAgorot: number;
  method: string;
}

export interface ShippingAddressPickerProps {
  /** Deal ID used for fetching shipping quotes. */
  dealId: string;
  /** SKU ID for the deal being purchased (required to compute shipping quotes). */
  dealSkuId: string | null;
  /** CSRF token from session cookie. */
  csrfToken: string;
  /** Called whenever the selected address changes (null = none selected). */
  onSelect(addressId: string | null): void;
  /** Called whenever shipping quotes update (empty = no ITEM deals or no address). */
  onQuotesChange?(quotes: ShippingQuote[]): void;
}

// ─── New address form state ───────────────────────────────────────────────────

interface AddressForm {
  recipientName: string;
  recipientPhone: string;
  cityCode: string;
  cityName: string;
  streetCode: string;
  streetName: string;
  houseNumber: string;
  apt: string;
  entrance: string;
  floor: string;
  zip: string;
  zipValidated: boolean;
  notes: string;
}

const EMPTY_FORM: AddressForm = {
  recipientName: '',
  recipientPhone: '',
  cityCode: '',
  cityName: '',
  streetCode: '',
  streetName: '',
  houseNumber: '',
  apt: '',
  entrance: '',
  floor: '',
  zip: '',
  zipValidated: false,
  notes: '',
};

function addressToForm(a: ShippingAddress): AddressForm {
  return {
    recipientName: a.recipientName,
    recipientPhone: a.recipientPhone,
    cityCode: a.cityCode,
    cityName: a.cityName,
    streetCode: a.streetCode ?? '',
    streetName: a.streetName,
    houseNumber: a.houseNumber,
    apt: a.apt ?? '',
    entrance: a.entrance ?? '',
    floor: a.floor ?? '',
    zip: a.zip ?? '',
    zipValidated: a.zipValidated ?? false,
    notes: a.notes ?? '',
  };
}

// ─── Component ────────────────────────────────────────────────────────────────

export function ShippingAddressPicker({
  dealId,
  dealSkuId,
  csrfToken,
  onSelect,
  onQuotesChange,
}: ShippingAddressPickerProps) {
  const t = useT('checkout_shipping');
  const tCommon = useT('common');

  const [addresses, setAddresses] = useState<ShippingAddress[]>([]);
  const [selected, setSelected] = useState<string | null>(null);
  // Start true so no flash of empty state before first fetch completes
  const [loadingAddresses, setLoadingAddresses] = useState(true);
  const [errorLoad, setErrorLoad] = useState(false);

  const [quotes, setQuotes] = useState<ShippingQuote[]>([]);
  const [loadingQuote, setLoadingQuote] = useState(false);
  const [errorQuote, setErrorQuote] = useState(false);

  const [dialogOpen, setDialogOpen] = useState(false);
  const [editingId, setEditingId] = useState<string | null>(null);
  const [form, setForm] = useState<AddressForm>(EMPTY_FORM);
  const [saving, setSaving] = useState(false);
  const [errorSave, setErrorSave] = useState(false);

  const [deleteConfirmId, setDeleteConfirmId] = useState<string | null>(null);
  const [deleting, setDeleting] = useState(false);
  const [errorDelete, setErrorDelete] = useState(false);

  // ── Load saved addresses on mount ──────────────────────────────────────────

  useEffect(() => {
    let cancelled = false;
    void (async () => {
      try {
        const r = await fetch('/api/shipping-addresses');
        if (!r.ok) throw new Error('fetch failed');
        const data = (await r.json()) as { ok: boolean; addresses: ShippingAddress[] };
        const rows = data.addresses;
        if (cancelled) return;
        setErrorLoad(false);
        setAddresses(rows);
        const def = rows.find((a) => a.isDefault) ?? rows[0] ?? null;
        if (def) {
          setSelected(def.id);
          onSelect(def.id);
        } else {
          onSelect(null);
        }
        setLoadingAddresses(false);
      } catch (err) {
        captureCaught(err, {
          scope: 'features.checkout.ShippingAddressPicker.loadAddresses',
          severity: 'warning',
        });
        if (!cancelled) {
          setErrorLoad(true);
          setLoadingAddresses(false);
        }
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [onSelect]);

  // ── Fetch shipping quote whenever address selection changes ────────────────

  const fetchQuote = useCallback(
    (addressId: string) => {
      setLoadingQuote(true);
      setErrorQuote(false);
      fetch('/api/checkout/shipping-quote', {
        method: 'POST',
        headers: {
          'content-type': 'application/json',
          'x-csrf-token': csrfToken,
        },
        body: JSON.stringify({
          cartItems: dealSkuId ? [{ dealId, skuId: dealSkuId, qty: 1 }] : [],
          shippingAddressId: addressId,
        }),
      })
        .then((r) => {
          if (!r.ok) throw new Error('quote failed');
          return r.json() as Promise<{
            ok: boolean;
            quote: Array<{ dealId: string; shippingAgorot: number; mode: string }>;
          }>;
        })
        .then(({ quote }) => {
          const q: ShippingQuote[] = quote.map((e) => ({
            dealId: e.dealId,
            vendorName: '',
            costAgorot: e.shippingAgorot,
            method: e.mode,
          }));
          setQuotes(q);
          onQuotesChange?.(q);
        })
        .catch((err) => {
          captureCaught(err, {
            scope: 'features.checkout.ShippingAddressPicker.fetchQuote',
            severity: 'warning',
          });
          setErrorQuote(true);
          setQuotes([]);
          onQuotesChange?.([]);
        })
        .finally(() => setLoadingQuote(false));
    },
    [dealId, dealSkuId, csrfToken, onQuotesChange],
  );

  useEffect(() => {
    const id = selected;
    // Defer state update out of synchronous effect body
    const timer = setTimeout(() => {
      if (id) {
        fetchQuote(id);
      } else {
        setQuotes([]);
        onQuotesChange?.([]);
      }
    }, 0);
    return () => clearTimeout(timer);
  }, [fetchQuote, onQuotesChange, selected]);

  // ── Address selection handler ──────────────────────────────────────────────

  function pick(id: string) {
    setSelected(id);
    onSelect(id);
  }

  // ── Open dialog for add / edit ─────────────────────────────────────────────

  function openAddDialog() {
    setEditingId(null);
    setForm(EMPTY_FORM);
    setErrorSave(false);
    setDialogOpen(true);
  }

  function openEditDialog(address: ShippingAddress) {
    setEditingId(address.id);
    setForm(addressToForm(address));
    setErrorSave(false);
    setDialogOpen(true);
  }

  function handleDialogOpenChange(open: boolean) {
    setDialogOpen(open);
    if (!open) {
      setEditingId(null);
      setForm(EMPTY_FORM);
      setErrorSave(false);
    }
  }

  // ── Save new or edited address ─────────────────────────────────────────────

  async function handleSave(e: SubmitEvent<HTMLFormElement>) {
    e.preventDefault();
    setSaving(true);
    setErrorSave(false);
    try {
      const existing = editingId ? addresses.find((a) => a.id === editingId) : null;
      const body = {
        recipientName: form.recipientName,
        recipientPhone: normalizeIlPhone(form.recipientPhone),
        cityCode: form.cityCode,
        cityName: form.cityName,
        ...(form.streetCode && { streetCode: form.streetCode }),
        streetName: form.streetName,
        houseNumber: form.houseNumber,
        zip: form.zip,
        zipValidated: form.zipValidated,
        ...(form.apt && { apt: form.apt }),
        ...(form.entrance && { entrance: form.entrance }),
        ...(form.floor && { floor: form.floor }),
        ...(form.notes && { notes: form.notes }),
        isDefault: existing?.isDefault ?? addresses.length === 0,
      };
      const res = await fetch(
        editingId ? `/api/shipping-addresses/${editingId}` : '/api/shipping-addresses',
        {
          method: editingId ? 'PUT' : 'POST',
          headers: {
            'content-type': 'application/json',
            'x-csrf-token': csrfToken,
          },
          body: JSON.stringify(body),
        },
      );
      if (!res.ok) throw new Error('save failed');
      const { address: saved } = (await res.json()) as { ok: boolean; address: ShippingAddress };
      if (editingId) {
        setAddresses((prev) => prev.map((a) => (a.id === editingId ? saved : a)));
        setEditingId(null);
      } else {
        setAddresses((prev) => [...prev, saved]);
        setSelected(saved.id);
        onSelect(saved.id);
      }
      setForm(EMPTY_FORM);
      setDialogOpen(false);
    } catch (err) {
      captureCaught(err, {
        scope: editingId
          ? 'features.checkout.ShippingAddressPicker.handleUpdate'
          : 'features.checkout.ShippingAddressPicker.handleSave',
        severity: 'warning',
      });
      setErrorSave(true);
    } finally {
      setSaving(false);
    }
  }

  // ── Delete address ─────────────────────────────────────────────────────────

  async function handleDelete(id: string) {
    setDeleting(true);
    setErrorDelete(false);
    try {
      const res = await fetch(`/api/shipping-addresses/${id}`, {
        method: 'DELETE',
        headers: { 'x-csrf-token': csrfToken },
      });
      if (!res.ok) throw new Error('delete failed');
      setAddresses((prev) => prev.filter((a) => a.id !== id));
      if (selected === id) {
        setSelected(null);
        onSelect(null);
      }
      setDeleteConfirmId(null);
    } catch (err) {
      captureCaught(err, {
        scope: 'features.checkout.ShippingAddressPicker.handleDelete',
        severity: 'warning',
      });
      setErrorDelete(true);
    } finally {
      setDeleting(false);
    }
  }

  function setField(field: keyof AddressForm) {
    return (e: React.ChangeEvent<HTMLInputElement>) =>
      setForm((prev) => ({ ...prev, [field]: e.target.value }));
  }

  // ── Shipping cost summary ──────────────────────────────────────────────────

  const totalShipping = quotes.reduce((sum, q) => sum + q.costAgorot, 0);

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

  return (
    <Card padding="md" className="mt-4">
      <h2 className="text-text-primary mb-3 text-base font-semibold">{t('title')}</h2>

      {loadingAddresses && (
        <div className="flex items-center gap-2 py-2">
          <Spinner size="sm" />
          <span className="text-text-secondary text-sm">{t('loading_addresses')}</span>
        </div>
      )}

      {!loadingAddresses && errorLoad && <InlineNotice tone="danger" title={t('error_load')} />}

      {!loadingAddresses && !errorLoad && (
        <>
          {addresses.length === 0 ? (
            <p className="text-text-secondary mb-3 text-sm">{t('no_addresses')}</p>
          ) : (
            <RadioGroup
              value={selected ?? ''}
              onValueChange={pick}
              aria-label={t('address_group_aria')}
              className="mb-3"
            >
              {addresses.map((a) => (
                <div key={a.id} className="flex items-center justify-between gap-2">
                  <RadioItem
                    value={a.id}
                    id={`addr-${a.id}`}
                    className="min-w-0 flex-1"
                    label={
                      <span className="text-sm">
                        {formatIsraeliAddress({
                          streetName: a.streetName,
                          houseNumber: a.houseNumber,
                          apt: a.apt,
                          cityName: a.cityName,
                        })}
                        {a.zip ? ` ${a.zip}` : ''} — {a.recipientName}
                      </span>
                    }
                  />
                  <div className="flex shrink-0 items-center gap-1">
                    <IconButton
                      variant="ghost"
                      size="sm"
                      type="button"
                      aria-label={t('address_edit')}
                      className="text-text-secondary"
                      onClick={() => openEditDialog(a)}
                    >
                      <Pencil size={14} aria-hidden />
                    </IconButton>
                    <IconButton
                      variant="ghost"
                      size="sm"
                      type="button"
                      aria-label={t('address_remove')}
                      className="text-text-secondary"
                      onClick={() => {
                        setErrorDelete(false);
                        setDeleteConfirmId(a.id);
                      }}
                    >
                      <Trash2 size={14} aria-hidden />
                    </IconButton>
                  </div>
                </div>
              ))}
            </RadioGroup>
          )}

          {errorDelete && <InlineNotice tone="danger" title={t('error_save')} className="mb-3" />}

          {/* Add / edit address dialog */}
          <Dialog open={dialogOpen} onOpenChange={handleDialogOpenChange}>
            <DialogTrigger asChild>
              <Button variant="secondary" size="sm" type="button" onClick={openAddDialog}>
                {t('add_address')}
              </Button>
            </DialogTrigger>
            <DialogContent>
              <DialogTitle>{editingId ? t('address_edit') : t('add_address_title')}</DialogTitle>
              <DialogDescription className="sr-only">{t('add_address_title')}</DialogDescription>
              <form onSubmit={handleSave} className="mt-4 flex flex-col gap-3">
                <div className="flex flex-col gap-1">
                  <Label htmlFor="shp-recipient-name">{t('recipient_name')}</Label>
                  <Input
                    id="shp-recipient-name"
                    value={form.recipientName}
                    onChange={setField('recipientName')}
                    required
                    autoComplete="name"
                  />
                </div>
                <div className="flex flex-col gap-1">
                  <Label htmlFor="shp-phone">{t('recipient_phone')}</Label>
                  <Input
                    id="shp-phone"
                    value={form.recipientPhone}
                    onChange={setField('recipientPhone')}
                    required
                    type="tel"
                    autoComplete="tel"
                    dir="ltr"
                  />
                </div>
                <div className="flex gap-2">
                  <div className="flex flex-1 flex-col gap-1">
                    <Label htmlFor="shp-city">{t('city')}</Label>
                    <Input
                      id="shp-city"
                      value={form.cityName}
                      onChange={setField('cityName')}
                      required
                      autoComplete="address-level2"
                    />
                  </div>
                  <div className="flex flex-1 flex-col gap-1">
                    <Label htmlFor="shp-city-code">{t('city_code')}</Label>
                    <Input
                      id="shp-city-code"
                      value={form.cityCode}
                      onChange={setField('cityCode')}
                      required
                      dir="ltr"
                    />
                  </div>
                </div>
                <div className="flex flex-col gap-1">
                  <Label htmlFor="shp-street">{t('street')}</Label>
                  <Input
                    id="shp-street"
                    value={form.streetName}
                    onChange={setField('streetName')}
                    required
                    autoComplete="address-line1"
                  />
                </div>
                <div className="flex flex-col gap-1">
                  <Label htmlFor="shp-zip">
                    {t('zip')}{' '}
                    <span aria-hidden="true" className="text-text-secondary text-xs">
                      ({t('zip_hint')})
                    </span>
                  </Label>
                  <Input
                    id="shp-zip"
                    value={form.zip}
                    onChange={(e) => {
                      // Only allow digits
                      const val = e.target.value.replace(/\D/g, '');
                      setForm((prev) => ({ ...prev, zip: val }));
                    }}
                    required
                    dir="ltr"
                    maxLength={7}
                    minLength={7}
                    pattern="[0-9]{7}"
                    inputMode="numeric"
                    autoComplete="postal-code"
                    title={t('zip_hint')}
                  />
                </div>
                <div className="flex gap-2">
                  <div className="flex flex-1 flex-col gap-1">
                    <Label htmlFor="shp-house">{t('house_number')}</Label>
                    <Input
                      id="shp-house"
                      value={form.houseNumber}
                      onChange={setField('houseNumber')}
                      required
                      dir="ltr"
                    />
                  </div>
                  <div className="flex flex-1 flex-col gap-1">
                    <Label htmlFor="shp-apt">{t('apt')}</Label>
                    <Input id="shp-apt" value={form.apt} onChange={setField('apt')} dir="ltr" />
                  </div>
                </div>
                <div className="flex gap-2">
                  <div className="flex flex-1 flex-col gap-1">
                    <Label htmlFor="shp-entrance">{t('entrance')}</Label>
                    <Input
                      id="shp-entrance"
                      value={form.entrance}
                      onChange={setField('entrance')}
                      dir="ltr"
                    />
                  </div>
                  <div className="flex flex-1 flex-col gap-1">
                    <Label htmlFor="shp-floor">{t('floor')}</Label>
                    <Input
                      id="shp-floor"
                      value={form.floor}
                      onChange={setField('floor')}
                      dir="ltr"
                    />
                  </div>
                </div>
                <div className="flex flex-col gap-1">
                  <Label htmlFor="shp-notes">{t('notes')}</Label>
                  <Input id="shp-notes" value={form.notes} onChange={setField('notes')} />
                </div>
                {errorSave && <InlineNotice tone="danger" title={t('error_save')} />}
                <Button type="submit" disabled={saving} className="mt-2 w-full">
                  {saving ? t('saving') : t('save_address')}
                </Button>
              </form>
            </DialogContent>
          </Dialog>

          <AlertDialog
            open={deleteConfirmId !== null}
            onOpenChange={(open) => {
              if (!open) {
                setDeleteConfirmId(null);
                setErrorDelete(false);
              }
            }}
          >
            <AlertDialogContent>
              <AlertDialogHeader>
                <AlertDialogTitle>{t('address_remove')}</AlertDialogTitle>
                <AlertDialogDescription>{t('address_remove_confirm')}</AlertDialogDescription>
              </AlertDialogHeader>
              {errorDelete && <InlineNotice tone="danger" title={t('error_save')} />}
              <AlertDialogFooter>
                <AlertDialogCancel disabled={deleting}>{tCommon('cancel')}</AlertDialogCancel>
                <AlertDialogAction
                  disabled={deleting || !deleteConfirmId}
                  onClick={() => {
                    if (deleteConfirmId) void handleDelete(deleteConfirmId);
                  }}
                >
                  {deleting ? t('saving') : t('address_remove')}
                </AlertDialogAction>
              </AlertDialogFooter>
            </AlertDialogContent>
          </AlertDialog>

          {/* Shipping quote */}
          {selected && (
            <div className="border-border-default mt-4 border-t pt-3">
              {loadingQuote && (
                <div className="flex items-center gap-2">
                  <Spinner size="sm" />
                  <span className="text-text-secondary text-sm">{t('shipping_quote_loading')}</span>
                </div>
              )}
              {!loadingQuote && errorQuote && (
                <InlineNotice tone="danger" title={t('error_quote')} />
              )}
              {!loadingQuote && !errorQuote && quotes.length > 0 && (
                <div className="flex items-center justify-between">
                  <span className="text-text-secondary text-sm">{t('shipping_cost')}</span>
                  {totalShipping === 0 ? (
                    <span className="text-sm font-medium text-green-600">{t('free_shipping')}</span>
                  ) : (
                    <span className="text-text-primary text-sm font-medium" aria-live="polite">
                      {formatAgorotShekels(totalShipping)}
                    </span>
                  )}
                </div>
              )}
            </div>
          )}
        </>
      )}
    </Card>
  );
}
