/**
 * VendorDeals — tabbed deal list for /vendor/deals (C2.2).
 *
 * 4 tabs: active / pending / closed / history.
 * Pending tab: VendorDealCard variant="pending" with fix-and-resubmit inline for REJECTED.
 * Closed tab: outcome filter chips (won/partial/lost).
 * Auth-gate vendor (server-side in .astro).
 */

'use client';

import { useMemo, useRef, type ReactNode } from 'react';
import { getDuplicateIdempotencyKey } from './duplicate-idempotency';
import { QueryBoundary } from '@platform-modules/ui-primitives';
import { useUrlFilterState } from '@/lib/url/useUrlFilterState';
import { makeVendorDealsCodec, type VendorDealsUrlState } from '@/lib/url/codecs/vendorDealsCodec';
import { HISTORY } from '@/lib/url/historyPolicy';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { HydratedIsland } from '@/components/HydratedIsland';
import { VendorShell } from '@/components/ui/layout/VendorShell';
import { VendorDealCard } from '@/components/ui/domain/vendor/VendorDealCard';
import { Button } from '@/components/ui/primitives/Button';
import { EmptyState } from '@/components/ui/feedback/EmptyState';
import { Icon } from '@/components/ui/icons/Icon';
import { DraftsList } from '@/components/ui/domain/DraftsList';
import { formatDealWindowEnd } from '@/lib/format';
import { useLocale, useT } from '@/lib/i18n/react';
import { Tabs } from '@/components/ui/layout/Tabs';
import { getCsrfToken } from '@/lib/csrf';
import { useToast } from '@/components/ui/overlays/Toast/useToast';
import { Skeleton, TableSkeleton } from '@/components/ui/feedback/Skeleton';
import type { DashboardPrefetchDescriptor } from '@/lib/query/prefetch-registry';

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

type TabKey = 'active' | 'pending' | 'closed' | 'history' | 'drafts';
type ClosedFilter = 'all' | 'won' | 'partial' | 'lost';
const VENDOR_DEALS_DEFAULT_TAB = 'active' as const;

interface ApiDeal {
  id: string;
  title: string;
  dealState: string;
  dealType?: string | null;
  quantityTotal: number;
  quantitySold: number;
  windowEnd?: string | null;
  rejectReason?: string | null;
  rejectionReason?: string | null;
  createdAt?: string | null;
  /** Set for GROUP deals — the group_deals.id needed for /vendor/group-deals/[id]. */
  groupDealId?: string | null;
}

// ─── Hook ─────────────────────────────────────────────────────────────────────

function useDraftCount() {
  return useQuery<number>({
    queryKey: ['vendor-draft-count'],
    queryFn: async () => {
      const res = await fetch('/api/vendor/deals/draft-count');
      if (!res.ok) return 0;
      const json = (await res.json()) as { ok: boolean; count: number };
      return json.count ?? 0;
    },
    staleTime: 60_000,
  });
}

function useVendorDeals(tab: Exclude<TabKey, 'drafts'>, options?: { enabled?: boolean }) {
  return useQuery<ApiDeal[]>({
    queryKey: vendorDealsQueryKey(tab),
    queryFn: () => fetchVendorDeals(tab),
    staleTime: 30_000,
    enabled: options?.enabled ?? true,
  });
}

export function vendorDealsQueryKey(tab: Exclude<TabKey, 'drafts'>) {
  return ['vendor-deals', tab] as const;
}

export async function fetchVendorDeals(tab: Exclude<TabKey, 'drafts'>): Promise<ApiDeal[]> {
  const res = await fetch(`/api/vendor/deals/list?tab=${tab}`);
  if (!res.ok) throw new Error('Failed to load deals');
  const json = (await res.json()) as { ok: boolean; deals: ApiDeal[] };
  return json.deals;
}

export const VENDOR_DEALS_PREFETCH_DESCRIPTOR: DashboardPrefetchDescriptor = {
  href: '/vendor/deals',
  queryKey: vendorDealsQueryKey(VENDOR_DEALS_DEFAULT_TAB),
  queryFn: () => fetchVendorDeals(VENDOR_DEALS_DEFAULT_TAB),
  staleTime: 30_000,
};

// ─── Helpers ──────────────────────────────────────────────────────────────────

function dealOutcome(deal: ApiDeal): 'won' | 'partial' | 'lost' {
  if (deal.dealState === 'SOLD_OUT') return 'won';
  const fill = deal.quantityTotal > 0 ? deal.quantitySold / deal.quantityTotal : 0;
  if (fill >= 0.5) return 'partial';
  return 'lost';
}

function emptyDescription(
  tab: Exclude<TabKey, 'drafts' | 'active'>,
  t: ReturnType<typeof useT<'vendor_deals'>>,
): string {
  if (tab === 'pending') return t('empty_pending_desc');
  if (tab === 'closed') return t('empty_closed_desc');
  if (tab === 'history') return t('empty_history_desc');
  return '';
}

// ─── Export wrapper ───────────────────────────────────────────────────────────

export function VendorDeals() {
  return (
    <HydratedIsland>
      <VendorDealsInner />
    </HydratedIsland>
  );
}

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

function VendorDealsInner() {
  const t = useT('vendor_deals');
  const codec = useMemo(() => makeVendorDealsCodec('/vendor/deals'), []);
  const { state: urlState, setUrlState } = useUrlFilterState<VendorDealsUrlState>({
    initial: { tab: 'active', closed: 'all' },
    codec,
  });
  const activeTab: TabKey = urlState.tab;
  const closedFilter: ClosedFilter = urlState.closed;
  const { data: draftCount = 0 } = useDraftCount();
  const { data: pendingDeals = [] } = useVendorDeals('pending');
  const { data: closedDeals = [] } = useVendorDeals('closed', {
    enabled: activeTab === 'closed',
  });

  const rejectedCount = pendingDeals.filter((d) => d.dealState === 'REJECTED').length;

  const dealTabPanels = useMemo(() => {
    const closedOutcomeCounts = {
      won: closedDeals.filter((d) => dealOutcome(d) === 'won').length,
      partial: closedDeals.filter((d) => dealOutcome(d) === 'partial').length,
      lost: closedDeals.filter((d) => dealOutcome(d) === 'lost').length,
    };

    const addDealButton = (
      <div className="flex justify-end">
        <Button
          variant="primary"
          size="sm"
          iconStart={<Icon name="Plus" size="sm" />}
          onClick={() => {
            window.location.href = '/vendor/deals/new';
          }}
        >
          {t('add_deal')}
        </Button>
      </div>
    );

    const closedFilterChips = (
      <div className="flex flex-wrap items-center gap-2">
        <span className="text-text-muted text-sm">{t('outcome_filter_label')}</span>
        <div className="flex gap-2" role="group" aria-label={t('outcome_filter')}>
          {(['all', 'won', 'partial', 'lost'] as ClosedFilter[]).map((f) => {
            const count =
              f === 'all'
                ? closedDeals.length
                : closedOutcomeCounts[f as 'won' | 'partial' | 'lost'];
            const label =
              f === 'all'
                ? `${t('filter_all')} (${count})`
                : `${t(`filter_${f}` as 'filter_won' | 'filter_partial' | 'filter_lost')} (${count})`;
            return (
              <Button
                key={f}
                aria-pressed={closedFilter === f}
                variant={closedFilter === f ? 'secondary' : 'ghost'}
                size="sm"
                onClick={() => setUrlState({ closed: f }, HISTORY.tweak)}
              >
                {label}
              </Button>
            );
          })}
        </div>
      </div>
    );

    const panelWrapper = (content: ReactNode, extras?: ReactNode) => (
      <div className="flex flex-col gap-4">
        {extras}
        {addDealButton}
        {content}
      </div>
    );

    const makeDealPanel = (tab: Exclude<TabKey, 'drafts'>) =>
      panelWrapper(
        <TabPanel
          tab={tab}
          closedFilter={closedFilter}
          tEmpty={t(
            `empty_${tab}` as 'empty_active' | 'empty_pending' | 'empty_closed' | 'empty_history',
          )}
          tEmptyDesc={
            tab === 'pending' || tab === 'closed' || tab === 'history'
              ? emptyDescription(tab, t)
              : ''
          }
          tAddDeal={t('add_deal')}
        />,
        tab === 'closed' ? closedFilterChips : undefined,
      );

    return {
      active: makeDealPanel('active'),
      pending: makeDealPanel('pending'),
      closed: makeDealPanel('closed'),
      history: makeDealPanel('history'),
      drafts: panelWrapper(<DraftsList bare />),
    };
  }, [closedFilter, closedDeals, t, setUrlState]);

  return (
    <VendorShell variant="dashboard" currentPath="/vendor/deals">
      <div className="flex flex-col gap-4 p-4 lg:p-6">
        <Tabs
          className="gap-4"
          items={[
            { value: 'active', label: t('tab_active') },
            {
              value: 'pending',
              label: t('tab_pending'),
              count: rejectedCount > 0 ? rejectedCount : undefined,
              warnAt: 0,
              dangerAt: 0,
            },
            {
              value: 'closed',
              label: t('tab_closed'),
              tooltip: t('tab_closed_tooltip'),
            },
            {
              value: 'history',
              label: t('tab_history'),
              tooltip: t('tab_history_tooltip'),
            },
            {
              value: 'drafts',
              label: t('tab_drafts'),
              count: draftCount > 0 ? draftCount : undefined,
            },
          ]}
          value={activeTab}
          onValueChange={(tab) => setUrlState({ tab: tab as TabKey }, HISTORY.tweak)}
          mode="vendor"
          ariaLabel={t('page_title')}
          panels={dealTabPanels}
        />
      </div>
    </VendorShell>
  );
}

// ─── Tab Panel ────────────────────────────────────────────────────────────────

interface TabPanelProps {
  tab: Exclude<TabKey, 'drafts'>;
  closedFilter: ClosedFilter;
  tEmpty: string;
  tEmptyDesc: string;
  tAddDeal: string;
}

function VendorDealsPanelSkeleton() {
  return (
    <div
      aria-hidden="true"
      className="flex flex-col gap-4"
      data-testid="instant-skeleton:vendor-deals"
    >
      <div className="flex justify-end">
        <Skeleton className="h-9 w-28" />
      </div>
      <TableSkeleton rows={4} cols={1} />
    </div>
  );
}

function TabPanel({ tab, closedFilter, tEmpty, tEmptyDesc, tAddDeal }: TabPanelProps) {
  const dealsQuery = useVendorDeals(tab);
  const qc = useQueryClient();
  const t = useT('vendor_deals');
  const tCard = useT('vendor_deal_card');
  const { locale } = useLocale();
  const { toast } = useToast();
  const duplicateKeys = useRef(new Map<string, string>());

  const duplicateMutation = useMutation({
    mutationFn: async ({ dealId, idempotencyKey }: { dealId: string; idempotencyKey: string }) => {
      const csrf = getCsrfToken();
      const res = await fetch(`/api/vendor/deals/${dealId}/duplicate`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-csrf-token': csrf,
          'idempotency-key': idempotencyKey,
        },
        body: '{}',
      });
      const json = (await res.json()) as { ok: boolean; deal?: { id: string } };
      if (!json.ok) throw new Error(t('duplicate_error'));
      return json.deal!;
    },
    onSuccess: (newDeal) => {
      void qc.invalidateQueries({ queryKey: ['vendor-deals', 'drafts'] });
      window.location.href = `/vendor/deals/${newDeal.id}`;
    },
    onError: () => {
      toast({ title: t('duplicate_error'), tone: 'danger' });
    },
  });

  return (
    <QueryBoundary
      query={dealsQuery}
      skeleton={<VendorDealsPanelSkeleton />}
      errorFallback={() => (
        <EmptyState
          title={t('error_title')}
          description={t('error_desc')}
          action={
            <Button variant="primary" size="sm" onClick={() => window.location.reload()}>
              {t('retry')}
            </Button>
          }
        />
      )}
    >
      {(deals) => {
        const filtered =
          tab === 'closed' && closedFilter !== 'all'
            ? deals.filter((d) => dealOutcome(d) === closedFilter)
            : deals;

        if (filtered.length === 0) {
          return (
            <EmptyState
              title={tEmpty}
              description={tEmptyDesc}
              action={
                tab === 'active' ? (
                  <Button
                    variant="primary"
                    size="sm"
                    onClick={() => {
                      window.location.href = '/vendor/deals/new';
                    }}
                  >
                    {tAddDeal}
                  </Button>
                ) : undefined
              }
            />
          );
        }

        return (
          <ul className="flex flex-col gap-3" data-testid="instant-content:vendor-deals">
            {filtered.map((deal) => {
              const variant =
                tab === 'active'
                  ? 'active'
                  : tab === 'pending'
                    ? 'pending'
                    : tab === 'history'
                      ? 'history'
                      : 'closed';

              const outcome = tab === 'closed' || tab === 'history' ? dealOutcome(deal) : undefined;
              const rejectionReason = deal.rejectionReason ?? deal.rejectReason ?? undefined;
              const isRejected = deal.dealState === 'REJECTED';
              const isGroupDeal = deal.dealType === 'GROUP';
              const groupMeta = isGroupDeal
                ? t('group_participants')
                    .replace('{{count}}', String(deal.quantitySold))
                    .replace('{{target}}', String(deal.quantityTotal))
                : undefined;

              return (
                <li key={deal.id}>
                  <VendorDealCard
                    variant={variant as 'active' | 'pending' | 'closed' | 'history'}
                    title={deal.title}
                    dealType={deal.dealType}
                    meta={
                      isGroupDeal
                        ? `${t('group_deal_badge')}${groupMeta ? ` · ${groupMeta}` : ''}`
                        : undefined
                    }
                    participants={deal.quantitySold}
                    targetParticipants={deal.quantityTotal}
                    outcome={outcome}
                    rejectionReason={isRejected ? rejectionReason : undefined}
                    issueCount={isRejected ? 1 : 0}
                    onFixResubmit={
                      isRejected
                        ? () => {
                            window.location.href = `/vendor/deals/${deal.id}`;
                          }
                        : undefined
                    }
                    timeRemaining={
                      deal.windowEnd
                        ? formatDealWindowEnd(deal.windowEnd, locale, {
                            endsAtTime: tCard('ends_at_time'),
                            endsOnDateTime: tCard('ends_on_datetime'),
                            endsInDays: tCard('ends_in_days'),
                          })
                        : undefined
                    }
                    submittedAt={tab === 'pending' ? (deal.createdAt ?? undefined) : undefined}
                    onDuplicate={
                      tab === 'closed' || tab === 'history'
                        ? () =>
                            duplicateMutation.mutate({
                              dealId: deal.id,
                              idempotencyKey: getDuplicateIdempotencyKey(
                                duplicateKeys.current,
                                deal.id,
                              ),
                            })
                        : undefined
                    }
                    duplicateLoading={
                      duplicateMutation.isPending && duplicateMutation.variables?.dealId === deal.id
                    }
                  />
                  {isGroupDeal && deal.groupDealId && (
                    <a
                      href={`/vendor/group-deals/${deal.groupDealId}`}
                      className="text-brand-primary-600 focus-visible:outline-brand-primary-600 mt-1 flex items-center gap-1 text-sm font-medium hover:underline focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2"
                      aria-label={`${t('manage_group_deal_aria')} ${deal.title}`}
                    >
                      <Icon name="BarChart3" size="sm" aria-hidden={true} />
                      {t('manage_group_deal')}
                    </a>
                  )}
                </li>
              );
            })}
          </ul>
        );
      }}
    </QueryBoundary>
  );
}
