/**
 * VendorSettings — single-page settings with SettingsNav anchor rail (C2.5).
 *
 * Sections: shop / pickup / payments / notifications / team
 * - shop: businessName + description
 * - pickup: toggle + address
 * - payments: StripeOnboarding
 * - notifications: NotificationsToggleList
 * - team: placeholder (empty state)
 *
 * Layout: SettingsNav left-rail on lg+, horizontal chip row on mobile.
 * SettingsNav tracks active section via IntersectionObserver.
 */

'use client';

import { useCallback, useState, useEffect, useRef } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query';
import { HydratedIsland } from '@/components/HydratedIsland';
import { createOptimisticMutation } from '@/lib/query/optimistic';
import { qk } from '@/lib/query/keys';
import { VendorShell } from '@/components/ui/layout/VendorShell';
import { SettingsNav } from '@/components/ui/layout/SettingsNav';
import { SettingsSection } from '@/components/ui/layout/SettingsSection';
import { NotificationsToggleList } from '@/components/ui/domain/NotificationsToggleList';
import type { NotificationItem } from '@/components/ui/domain/NotificationsToggleList';
import { Button } from '@/components/ui/primitives/Button';
import { Input } from '@/components/ui/primitives/Input';
import { NumberInput } from '@/components/ui/primitives/NumberInput';
import { Textarea } from '@/components/ui/primitives/Textarea';
import { FormField } from '@/components/ui/primitives/FormField';
import { Switch } from '@/components/ui/primitives/Switch';
import { Label } from '@/components/ui/primitives/Label';
import { EmptyState } from '@/components/ui/feedback/EmptyState';
import { ErrorState } from '@/components/ui/feedback/ErrorState';
import { InlineNotice } from '@/components/ui/feedback/InlineNotice';
import { VendorSettingsSkeleton, SkeletonGuard, Skeleton } from '@/components/ui/feedback/Skeleton';
import { useT } from '@/lib/i18n/react';
import { getCsrfToken } from '@/lib/csrf';
import { captureCaught } from '@/lib/observability';
import { notify } from '@/lib/query/toast-bridge';
import { useToast } from '@/components/ui/overlays/Toast/useToast';
import {
  useVendorAddresses,
  deleteVendorAddress,
  useInvalidateVendorAddresses,
  type VendorAddress,
} from '@/features/vendor-pickup/useVendorAddresses';
import { PickupAddressSelector } from '@/components/ui/domain/PickupAddressSelector';
import { AddressCard } from '@/components/ui/domain/AddressCard';
import { Trash2 } from 'lucide-react';
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
} from '@/components/ui/overlays/AlertDialog';
import { VendorSettingsRouteNav } from '@/features/vendor-settings/VendorSettingsRouteNav';

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

interface ReturnAddress {
  line1: string;
  line2?: string;
  city: string;
  postal: string;
  country: string;
}

interface VendorProfile {
  id: string;
  businessName: string;
  displayName: string;
  description?: string | null;
  stripeAccountId?: string | null;
  stripeChargesEnabled?: boolean | null;
  selfPickup?: boolean | null;
  pickupAddress?: string | null;
  returnAddress?: ReturnAddress | null;
  restockingFeePct?: string | null;
}

interface NotifPrefs {
  silentMode: boolean;
  alertEverySale: boolean;
  alertStockOut: boolean;
  alertPersonalDeal: boolean;
  alertTeamMessage: boolean;
}

// ─── Hooks ────────────────────────────────────────────────────────────────────

function useVendorProfile() {
  return useQuery<VendorProfile>({
    queryKey: qk.vendorProfile(),
    queryFn: async () => {
      const res = await fetch('/api/vendor/profile');
      if (!res.ok) throw new Error('Failed to load profile');
      const json = (await res.json()) as { ok: boolean; vendor: VendorProfile };
      return json.vendor;
    },
    staleTime: 60_000,
  });
}

function useNotifPrefs() {
  return useQuery<NotifPrefs>({
    queryKey: ['vendor-notif-prefs'],
    queryFn: async () => {
      const res = await fetch('/api/vendor/notifications/settings');
      if (!res.ok) throw new Error('Failed to load notification prefs');
      const json = (await res.json()) as { ok: boolean; prefs: NotifPrefs };
      return (
        json.prefs ?? {
          silentMode: false,
          alertEverySale: true,
          alertStockOut: true,
          alertPersonalDeal: true,
          alertTeamMessage: true,
        }
      );
    },
    staleTime: 60_000,
  });
}

// ─── Main Component ───────────────────────────────────────────────────────────

type VendorSettingsPanel = 'notifications';

function VendorSettingsInner({ panel }: { panel?: VendorSettingsPanel }) {
  const t = useT('vendor_settings_full');
  const { data: profile, isLoading, isError } = useVendorProfile();
  const [activeSection, setActiveSection] = useState<string>('shop');
  const mainRef = useRef<HTMLDivElement>(null);

  // IntersectionObserver to track which section is visible (only when
  // rendering the full unified settings page — single-panel routes skip).
  useEffect(() => {
    if (panel) return;
    const sectionIds = ['shop', 'pickup', 'returns', 'payments', 'notifications', 'team'];
    const observers: IntersectionObserver[] = [];

    sectionIds.forEach((id) => {
      const el = document.getElementById(id);
      if (!el) return;
      const obs = new IntersectionObserver(
        ([entry]) => {
          if (entry?.isIntersecting) setActiveSection(id);
        },
        { rootMargin: '-30% 0px -60% 0px', threshold: 0 },
      );
      obs.observe(el);
      observers.push(obs);
    });

    return () => observers.forEach((obs) => obs.disconnect());
  }, [profile, panel]);

  const sections = [
    { id: 'shop', labelKey: 'section_shop' as const },
    { id: 'pickup', labelKey: 'section_pickup' as const },
    { id: 'returns', labelKey: 'section_returns' as const },
    { id: 'payments', labelKey: 'section_payments' as const },
    { id: 'notifications', labelKey: 'section_notifications' as const },
    { id: 'team', labelKey: 'section_team' as const },
  ];

  const currentPath = panel ? `/vendor/settings/${panel}` : '/vendor/settings';

  if (isLoading && !profile) {
    return (
      <VendorShell variant="dashboard" currentPath={currentPath}>
        <div aria-busy="true" role="status">
          <span className="sr-only">{t('loading')}</span>
          <SkeletonGuard delay={0}>
            <VendorSettingsSkeleton />
          </SkeletonGuard>
        </div>
      </VendorShell>
    );
  }

  if (isError) {
    return (
      <VendorShell variant="dashboard" currentPath={currentPath}>
        <ErrorState
          title={t('load_error_title')}
          description={t('load_error_description')}
          className="py-16"
        />
      </VendorShell>
    );
  }

  // Single-panel mode — render only the requested section, no nav rail.
  if (panel === 'notifications') {
    return (
      <VendorShell variant="dashboard" currentPath={currentPath}>
        <div className="mx-auto flex max-w-2xl flex-col gap-6 p-4 lg:p-6">
          <VendorSettingsRouteNav activeId="notifications" />
          <SettingsSection id="notifications" title={t('section_notifications')}>
            <NotificationsSection />
          </SettingsSection>
        </div>
      </VendorShell>
    );
  }

  return (
    <VendorShell variant="dashboard" currentPath={currentPath}>
      <div ref={mainRef} className="flex gap-6 p-4 lg:p-6">
        {/* SettingsNav — left/right rail on lg+ */}
        <aside className="hidden lg:block lg:w-48 lg:shrink-0">
          <SettingsNav sections={sections} activeId={activeSection} className="sticky top-20" />
        </aside>

        {/* Mobile SettingsNav — horizontal chips above content */}
        <div className="w-full lg:hidden">
          <SettingsNav sections={sections} activeId={activeSection} className="mb-4" />
          <SectionsContent profile={profile ?? null} />
        </div>

        {/* Desktop content */}
        <div className="hidden min-w-0 flex-1 flex-col gap-8 lg:flex">
          <SectionsContent profile={profile ?? null} />
        </div>
      </div>
    </VendorShell>
  );
}

// ─── Sections Content ─────────────────────────────────────────────────────────

function SectionsContent({ profile }: { profile: VendorProfile | null }) {
  const t = useT('vendor_settings_full');
  const tReturns = useT('returns');

  return (
    <div className="flex flex-col gap-8">
      {/* Shop */}
      <SettingsSection id="shop" title={t('section_shop')}>
        <ShopSection profile={profile} />
      </SettingsSection>

      {/* Pickup */}
      <SettingsSection id="pickup" title={t('section_pickup')}>
        <PickupSection profile={profile} />
      </SettingsSection>

      {/* Returns */}
      <SettingsSection id="returns" title={tReturns('vendorSettingsReturnsTitle')}>
        <ReturnsSection profile={profile} />
      </SettingsSection>

      {/* Payments */}
      <SettingsSection id="payments" title={t('section_payments')}>
        <PaymentsSection profile={profile} />
      </SettingsSection>

      {/* Notifications */}
      <SettingsSection id="notifications" title={t('section_notifications')}>
        <NotificationsSection />
      </SettingsSection>

      {/* Team */}
      <SettingsSection id="team" title={t('section_team')}>
        <EmptyState title={t('team_empty')} description={t('team_empty_desc')} />
      </SettingsSection>
    </div>
  );
}

// ─── Returns Section mutation ─────────────────────────────────────────────────

interface ReturnsPatchVars {
  returnAddress: ReturnAddress | null;
  restockingFeePct: number;
}

const useUpdateReturns = createOptimisticMutation<void, ReturnsPatchVars, VendorProfile>({
  mutationFn: async (vars) => {
    const csrf = getCsrfToken();
    const res = await fetch('/api/vendor/profile', {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json', 'x-csrf-token': csrf },
      body: JSON.stringify({
        returnAddress: vars.returnAddress,
        // Convert display percent to fraction for the API
        restockingFeePct: vars.restockingFeePct / 100,
      }),
    });
    if (res.status === 422) {
      const json = (await res.json()) as { code?: string };
      if (json.code === 'RETURN_ADDRESS_REQUIRED') {
        throw Object.assign(new Error('RETURN_ADDRESS_REQUIRED'), {
          code: 'RETURN_ADDRESS_REQUIRED',
        });
      }
    }
    if (!res.ok) throw new Error('Save failed');
  },
  queryKey: qk.vendorProfile(),
  optimisticUpdate: (prev, vars) =>
    prev
      ? {
          ...prev,
          returnAddress: vars.returnAddress,
          restockingFeePct: String(vars.restockingFeePct / 100),
        }
      : ({
          returnAddress: vars.returnAddress,
          restockingFeePct: String(vars.restockingFeePct / 100),
        } as VendorProfile),
  errorToast: () => '',
  successToast: () => null,
});

// ─── Returns Section ──────────────────────────────────────────────────────────

function ReturnsSection({ profile }: { profile: VendorProfile | null }) {
  const t = useT('returns');
  const tSettings = useT('vendor_settings_full');

  const [line1, setLine1] = useState(profile?.returnAddress?.line1 ?? '');
  const [hadAddressInitially] = useState(
    () => (profile?.returnAddress?.line1 ?? '').trim().length > 0,
  );
  const [line2, setLine2] = useState(profile?.returnAddress?.line2 ?? '');
  const [city, setCity] = useState(profile?.returnAddress?.city ?? '');
  const [postal, setPostal] = useState(profile?.returnAddress?.postal ?? '');
  const [country, setCountry] = useState(profile?.returnAddress?.country ?? 'IL');
  // Display as percent (0..5), API stores as fraction (0..0.05)
  const [feePct, setFeePct] = useState(() => {
    const raw = parseFloat(profile?.restockingFeePct ?? '0');
    return isNaN(raw) ? 0 : raw * 100;
  });
  const [addrError, setAddrError] = useState<string | null>(null);
  const [savedSuccessfully, setSavedSuccessfully] = useState(false);

  const isDirty =
    !profile ||
    line1 !== (profile.returnAddress?.line1 ?? '') ||
    line2 !== (profile.returnAddress?.line2 ?? '') ||
    city !== (profile.returnAddress?.city ?? '') ||
    postal !== (profile.returnAddress?.postal ?? '') ||
    country !== (profile.returnAddress?.country ?? 'IL') ||
    feePct !==
      (() => {
        const raw = parseFloat(profile.restockingFeePct ?? '0');
        return isNaN(raw) ? 0 : raw * 100;
      })();

  function markReturnsDirty() {
    setSavedSuccessfully(false);
  }

  useEffect(() => {
    if (profile) {
      void Promise.resolve().then(() => {
        setLine1(profile.returnAddress?.line1 ?? '');

        setLine2(profile.returnAddress?.line2 ?? '');

        setCity(profile.returnAddress?.city ?? '');

        setPostal(profile.returnAddress?.postal ?? '');

        setCountry(profile.returnAddress?.country ?? 'IL');
        const raw = parseFloat(profile.restockingFeePct ?? '0');
        setFeePct(isNaN(raw) ? 0 : raw * 100);
      });
    }
  }, [profile]);

  const mutation = useUpdateReturns();

  const hasAddress = line1.trim().length > 0;
  const returnAddress: ReturnAddress | null = hasAddress
    ? {
        line1: line1.trim(),
        line2: line2.trim() || undefined,
        city: city.trim(),
        postal: postal.trim(),
        country: country.trim() || 'IL',
      }
    : null;

  async function handleSave() {
    setAddrError(null);
    try {
      await mutation.mutateAsync({ returnAddress, restockingFeePct: feePct });
      setSavedSuccessfully(true);
    } catch (err) {
      if (err instanceof Error && (err as { code?: string }).code === 'RETURN_ADDRESS_REQUIRED') {
        setAddrError(
          hadAddressInitially && !hasAddress
            ? t('returnAddressRequiredForPhysical')
            : t('returnAddressRequiredEmpty'),
        );
        return;
      }
      notify.error(tSettings('returns_save_error'));
    }
  }

  return (
    <div className="flex flex-col gap-4">
      <p className="text-text-secondary text-sm">{t('returns_section_intro')}</p>
      <FormField htmlFor="return-line1" label={t('returnAddressLine1')}>
        <Input
          id="return-line1"
          value={line1}
          onChange={(e) => {
            markReturnsDirty();
            setLine1(e.target.value);
          }}
          autoComplete="address-line1"
        />
      </FormField>
      <FormField htmlFor="return-line2" label={t('returnAddressLine2')}>
        <Input
          id="return-line2"
          value={line2}
          onChange={(e) => {
            markReturnsDirty();
            setLine2(e.target.value);
          }}
          autoComplete="address-line2"
        />
      </FormField>
      <div className="grid grid-cols-2 gap-3">
        <FormField htmlFor="return-city" label={t('returnAddressCity')}>
          <Input
            id="return-city"
            value={city}
            onChange={(e) => {
              markReturnsDirty();
              setCity(e.target.value);
            }}
            autoComplete="address-level2"
          />
        </FormField>
        <FormField htmlFor="return-postal" label={t('returnAddressPostal')}>
          <Input
            id="return-postal"
            value={postal}
            onChange={(e) => {
              markReturnsDirty();
              setPostal(e.target.value);
            }}
            autoComplete="postal-code"
          />
        </FormField>
      </div>
      <FormField htmlFor="return-country" label={t('returnAddressCountry')}>
        <Input
          id="return-country"
          value={tSettings('country_il')}
          readOnly
          autoComplete="country"
        />
      </FormField>
      <FormField
        htmlFor="return-fee-pct"
        label={t('restockingFeePctLabel')}
        tooltip={t('restockingFeePctHelp')}
      >
        <NumberInput
          id="return-fee-pct"
          step={0.5}
          min={0}
          max={5}
          value={feePct}
          onChange={(n) => {
            markReturnsDirty();
            setFeePct(n);
          }}
        />
      </FormField>
      {addrError && (
        <p role="alert" className="text-sm text-[var(--color-danger)]">
          {addrError}
        </p>
      )}
      <Button
        variant="primary"
        size="sm"
        loading={mutation.isPending}
        onClick={() => void handleSave()}
        className="self-start"
      >
        {savedSuccessfully && !isDirty ? t('returns_saved') : t('returns_save')}
      </Button>
    </div>
  );
}

// ─── Payments Section ─────────────────────────────────────────────────────────

function PaymentsSection({ profile }: { profile: VendorProfile | null }) {
  const t = useT('vendor_settings_full');
  if (!profile) return null;
  if (profile.stripeChargesEnabled) {
    return <InlineNotice tone="success" description={t('stripe_connected')} />;
  }
  if (profile.stripeAccountId && !profile.stripeChargesEnabled) {
    return (
      <div className="flex flex-col gap-3">
        <InlineNotice tone="info" description={t('stripe_pending_verification')} />
        <Button
          variant="primary"
          size="sm"
          className="self-start"
          onClick={() => void (window.location.href = '/vendor/settings/payments')}
        >
          {t('stripe_check_status')}
        </Button>
      </div>
    );
  }
  return (
    <div className="flex flex-col gap-3">
      <InlineNotice tone="info" description={t('stripe_connect_prompt')} />
      <Button
        variant="primary"
        size="sm"
        className="self-start"
        onClick={() => void (window.location.href = '/vendor/settings/payments')}
      >
        {t('stripe_connect_cta')}
      </Button>
    </div>
  );
}

// ─── Shop Section mutation ────────────────────────────────────────────────────

const useUpdateShopProfile = createOptimisticMutation<
  void,
  { businessName: string; description: string },
  VendorProfile
>({
  mutationFn: async (vars) => {
    const csrf = getCsrfToken();
    const res = await fetch('/api/vendor/profile', {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json', 'x-csrf-token': csrf },
      body: JSON.stringify(vars),
    });
    if (!res.ok) throw new Error('Save failed');
  },
  queryKey: qk.vendorProfile(),
  optimisticUpdate: (prev, vars) =>
    prev
      ? { ...prev, businessName: vars.businessName, description: vars.description }
      : ({ businessName: vars.businessName, description: vars.description } as VendorProfile),
  errorToast: () => '',
  successToast: () => null,
});

// ─── Shop Section ─────────────────────────────────────────────────────────────

function ShopSection({ profile }: { profile: VendorProfile | null }) {
  const t = useT('vendor_settings_full');
  const [name, setName] = useState(profile?.businessName ?? '');
  const [desc, setDesc] = useState(profile?.description ?? '');
  const [savedSuccessfully, setSavedSuccessfully] = useState(false);

  const isDirty = !profile || name !== profile.businessName || desc !== (profile.description ?? '');

  useEffect(() => {
    if (profile) {
      void Promise.resolve().then(() => {
        setName(profile.businessName);
        setDesc(profile.description ?? '');
      });
    }
  }, [profile]);

  const mutation = useUpdateShopProfile();

  return (
    <div className="flex flex-col gap-4">
      <FormField htmlFor="shop-name" label={t('shop_name_label')}>
        <Input
          id="shop-name"
          value={name}
          onChange={(e) => {
            setSavedSuccessfully(false);
            setName(e.target.value);
          }}
        />
      </FormField>
      <FormField htmlFor="shop-desc" label={t('shop_desc_label')}>
        <Textarea
          id="shop-desc"
          rows={3}
          value={desc}
          onChange={(e) => {
            setSavedSuccessfully(false);
            setDesc(e.target.value);
          }}
        />
      </FormField>
      <Button
        variant="primary"
        size="sm"
        loading={mutation.isPending}
        onClick={() =>
          void mutation
            .mutateAsync({ businessName: name, description: desc })
            .then(() => setSavedSuccessfully(true))
            .catch((err) => {
              captureCaught(err, { scope: 'features.vendor-settings.ShopSection.save' });
              notify.error(t('shop_save_error'));
            })
        }
        className="self-start"
      >
        {savedSuccessfully && !isDirty ? t('saved') : t('save')}
      </Button>
    </div>
  );
}

// ─── Pickup Section mutation ──────────────────────────────────────────────────

const useUpdatePickup = createOptimisticMutation<
  void,
  { selfPickup: boolean; pickupAddress?: string | null },
  VendorProfile
>({
  mutationFn: async (vars) => {
    const csrf = getCsrfToken();
    const res = await fetch('/api/vendor/profile', {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json', 'x-csrf-token': csrf },
      body: JSON.stringify(vars),
    });
    if (!res.ok) throw new Error('Save failed');
  },
  queryKey: qk.vendorProfile(),
  optimisticUpdate: (prev, vars) =>
    prev
      ? {
          ...prev,
          selfPickup: vars.selfPickup,
          pickupAddress: vars.pickupAddress ?? prev.pickupAddress,
        }
      : ({ selfPickup: vars.selfPickup } as VendorProfile),
  errorToast: () => '',
  successToast: () => null,
});

// ─── Pickup Section ───────────────────────────────────────────────────────────

function PickupSection({ profile }: { profile: VendorProfile | null }) {
  const t = useT('vendor_settings_full');
  const tCommon = useT('common');
  const { data: addresses = [], isLoading } = useVendorAddresses();
  const invalidate = useInvalidateVendorAddresses();
  const mutation = useUpdatePickup();
  const { toast } = useToast();
  const [selfPickup, setSelfPickup] = useState(profile?.selfPickup ?? false);
  const [deletingId, setDeletingId] = useState<string | null>(null);
  const [addressToDelete, setAddressToDelete] = useState<VendorAddress | null>(null);
  const [addPickerOpen, setAddPickerOpen] = useState(false);

  useEffect(() => {
    if (profile) {
      void Promise.resolve().then(() => setSelfPickup(profile.selfPickup ?? false));
    }
  }, [profile]);

  async function handleDelete(addr: VendorAddress) {
    setDeletingId(addr.id);
    try {
      const result = await deleteVendorAddress(addr.id);
      if (!result.ok) {
        if (result.code === 'ADDRESS_IN_USE') {
          toast({ title: t('pickup_address_in_use'), tone: 'danger' });
        } else {
          toast({ title: t('pickup_address_delete_error'), tone: 'danger' });
        }
        return;
      }
      await invalidate();
      if (selfPickup && addresses.length <= 1) {
        setSelfPickup(false);
        void mutation.mutateAsync({ selfPickup: false });
        toast({ title: t('pickup_disabled_no_addresses'), tone: 'warning' });
      }
    } finally {
      setDeletingId(null);
    }
  }

  async function handleToggle(value: boolean) {
    setSelfPickup(value);
    await mutation.mutateAsync({ selfPickup: value });
    toast({ title: t('pickup_toggle_saved'), tone: 'success' });
  }

  return (
    <div className="flex flex-col gap-4">
      <div className="flex items-center justify-between gap-3">
        <div className="min-w-0 flex-1">
          <Label htmlFor="pickup-toggle">{t('pickup_toggle_label')}</Label>
          <p className="text-text-muted mt-0.5 text-xs">{t('pickup_toggle_description')}</p>
        </div>
        <Switch
          id="pickup-toggle"
          checked={selfPickup}
          onCheckedChange={(v) =>
            void handleToggle(v).catch((err) => {
              captureCaught(err, { scope: 'features.vendor-settings.PickupSection.toggle' });
              notify.error(t('pickup_save_error'));
            })
          }
        />
      </div>

      {selfPickup && !isLoading && addresses.length === 0 && (
        <InlineNotice tone="warning" description={t('pickup_required_callout')} />
      )}

      <div className="flex flex-col gap-2">
        <p className="text-sm font-medium">{t('pickup_address_book_title')}</p>
        {isLoading ? null : addresses.length === 0 ? (
          <p className="text-text-muted text-sm">{t('pickup_address_empty')}</p>
        ) : (
          addresses.map((addr) => (
            <div key={addr.id} className="flex items-center gap-2">
              <div className="flex-1">
                <AddressCard label={addr.label} address={addr.fullAddress} />
              </div>
              <Button
                type="button"
                variant="ghost"
                size="sm"
                aria-label={t('pickup_address_delete')}
                loading={deletingId === addr.id}
                onClick={() => setAddressToDelete(addr)}
              >
                <Trash2 size={16} />
              </Button>
            </div>
          ))
        )}
      </div>

      <AlertDialog
        open={!!addressToDelete}
        onOpenChange={(open) => {
          if (!open) setAddressToDelete(null);
        }}
      >
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>{t('pickup_address_delete')}</AlertDialogTitle>
            <AlertDialogDescription>{t('pickup_address_delete_confirm')}</AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>{tCommon('cancel')}</AlertDialogCancel>
            <AlertDialogAction
              onClick={() => {
                if (addressToDelete) {
                  void handleDelete(addressToDelete);
                  setAddressToDelete(null);
                }
              }}
            >
              {t('pickup_address_delete')}
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>

      <Button
        type="button"
        variant="secondary"
        size="sm"
        className="self-start"
        onClick={() => setAddPickerOpen(true)}
      >
        {t('pickup_add_address')}
      </Button>

      {addPickerOpen && (
        <PickupAddressSelector
          value=""
          onChange={() => {
            void invalidate();
            setAddPickerOpen(false);
          }}
        />
      )}
    </div>
  );
}

// ─── Notifications Section ────────────────────────────────────────────────────

function NotificationsSection() {
  const t = useT('vendor_settings_full');
  const queryClient = useQueryClient();
  const { toast } = useToast();
  const { data: prefs, isLoading: prefsLoading, isError: prefsIsError } = useNotifPrefs();

  const [items, setItems] = useState<NotificationItem[]>([] as NotificationItem[]);

  const updatePref = useCallback(
    (key: keyof NotifPrefs, value: boolean) => {
      // Optimistic local update — revert on failure.
      setItems((prev) =>
        prev.map((item) => (item.key === key ? { ...item, enabled: value } : item)),
      );
      void (async () => {
        try {
          const csrf = getCsrfToken();
          const res = await fetch('/api/vendor/notifications/settings', {
            method: 'PATCH',
            headers: { 'Content-Type': 'application/json', 'x-csrf-token': csrf },
            body: JSON.stringify({ [key]: value }),
          });
          if (!res.ok) throw new Error(`PATCH failed: ${res.status}`);
        } catch (err) {
          captureCaught(err, { scope: 'features.vendor-settings.NotificationsSection.updatePref' });
          setItems((prev) =>
            prev.map((item) => (item.key === key ? { ...item, enabled: !value } : item)),
          );
          toast({ title: t('notif_update_error'), tone: 'danger' });
        }
      })();
    },
    [t, toast],
  );

  const buildItems = useCallback(
    (p: NotifPrefs): NotificationItem[] => {
      return [
        {
          key: 'alertEverySale',
          label: t('alert_every_sale_label'),
          description: t('alert_every_sale_desc'),
          enabled: p.alertEverySale,
          onChange: (v) => updatePref('alertEverySale', v),
        },
        {
          key: 'alertStockOut',
          label: t('alert_stock_out_label'),
          description: t('alert_stock_out_desc'),
          enabled: p.alertStockOut,
          onChange: (v) => updatePref('alertStockOut', v),
        },
        {
          key: 'alertPersonalDeal',
          label: t('alert_personal_deal_label'),
          description: t('alert_personal_deal_desc'),
          enabled: p.alertPersonalDeal,
          onChange: (v) => updatePref('alertPersonalDeal', v),
        },
      ];
    },
    [t, updatePref],
  );

  useEffect(() => {
    if (!prefs) return;

    void Promise.resolve().then(() => setItems(buildItems(prefs)));
  }, [buildItems, prefs]);

  async function handleSilentChange(silent: boolean) {
    const previous = queryClient.getQueryData<NotifPrefs>(['vendor-notif-prefs']);
    queryClient.setQueryData<NotifPrefs>(['vendor-notif-prefs'], (prev) =>
      prev ? { ...prev, silentMode: silent } : prev,
    );
    try {
      const csrf = getCsrfToken();
      const res = await fetch('/api/vendor/notifications/settings', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'x-csrf-token': csrf },
        body: JSON.stringify({ silentMode: silent }),
      });
      if (!res.ok) throw new Error(`POST failed: ${res.status}`);
    } catch (err) {
      captureCaught(err, {
        scope: 'features.vendor-settings.NotificationsSection.handleSilentChange',
      });
      if (previous) queryClient.setQueryData(['vendor-notif-prefs'], previous);
      toast({ title: t('notif_update_error'), tone: 'danger' });
    }
  }

  if (prefsIsError) {
    return <InlineNotice tone="danger" description={t('notif_load_error')} />;
  }

  if (prefsLoading && !prefs) {
    return (
      <div aria-busy="true" className="flex flex-col gap-3 py-1" role="status">
        <span className="sr-only">{t('loading')}</span>
        {Array.from({ length: 4 }, (_, i) => (
          <div key={i} className="flex items-center justify-between gap-3 py-3">
            <div className="min-w-0 flex-1 space-y-2">
              <Skeleton className="h-4 w-1/3" />
              <Skeleton variant="text" className="w-2/3" />
            </div>
            <Skeleton className="h-6 w-11 rounded-full" />
          </div>
        ))}
      </div>
    );
  }

  const displayItems = items.length > 0 || !prefs ? items : buildItems(prefs);

  return (
    <NotificationsToggleList
      items={displayItems}
      silentMode={prefs?.silentMode ?? false}
      onSilentModeChange={(v) => void handleSilentChange(v)}
    />
  );
}

// ─── Exported wrapper ─────────────────────────────────────────────────────────

export function VendorSettings({ panel }: { panel?: VendorSettingsPanel } = {}) {
  return (
    <HydratedIsland>
      <VendorSettingsInner panel={panel} />
    </HydratedIsland>
  );
}
