// src/features/admin-deal-detail/DealDetail.tsx
// Admin: deal drill-down page - overview, moderation, purchases, images, reviews.

'use client';

import { useState, useEffect, lazy, Suspense } from 'react';
import { getCsrfToken } from '@/lib/csrf';
import { useT, useLocale, LocaleProvider } from '@/lib/i18n/react';
import type { Locale } from '@/lib/i18n/index';
import { AdminDetailPage } from '@/components/ui/domain/admin/AdminDetailPage';
import { AdminTable } from '@/components/ui/domain/admin/AdminTable';
import { Pill } from '@/components/ui/primitives/Pill';
import { Image } from '@/components/ui/primitives/Image';
import { Button } from '@/components/ui/primitives/Button';
import { Stack } from '@/components/ui/layout/Stack';
import { Row } from '@/components/ui/layout/Row';
// Reject dialog primitives (Label/Textarea/Select) live in the lazy
// `./RejectDialog` chunk — do not import them here.
import { ErrorBoundary } from '@/components/ui/feedback/ErrorBoundary';
import { RetryPanel } from '@/components/ui/feedback/RetryPanel';
import { Skeleton } from '@/components/ui/feedback/Skeleton';
import { CategoryPillGroup } from '@/components/ui/domain/CategoryPillGroup/CategoryPillGroup';
import { TagPillGroup } from '@/components/ui/domain/TagPillGroup/TagPillGroup';
import { captureCaught } from '@/lib/observability';
import { formatDate } from '@/lib/format';
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/overlays/Tooltip/Tooltip';

// ─── Lazy-loaded moderation dialogs (route code-splitting C3) ─────────────
// Each `lazy()` call is paired with a callable `importX` so the chunk can be
// eagerly preloaded on hover/focus of the trigger button before the user
// actually clicks it. See route-code-splitting design spec C3.

const importRejectDialog = () =>
  import('./RejectDialog').then((m) => ({ default: m.RejectDialog }));
const RejectDialogLazy = lazy(importRejectDialog);

const importApproveDialog = () =>
  import('./ApproveDialog').then((m) => ({ default: m.ApproveDialog }));
const ApproveDialogLazy = lazy(importApproveDialog);

function DialogSkeleton() {
  return (
    <div
      role="status"
      aria-busy="true"
      className="fixed inset-0 z-50 flex items-center justify-center bg-black/40"
    >
      <div className="bg-surface-default mx-4 w-full max-w-md rounded-xl p-6 shadow-xl">
        <Stack gap="3">
          <Skeleton className="h-5 w-2/3" />
          <Skeleton className="h-4 w-full" />
          <Skeleton className="h-10 w-full" />
          <Skeleton className="h-20 w-full" />
        </Stack>
      </div>
    </div>
  );
}

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

export type RejectionReason =
  | 'WRONG_PRICE'
  | 'MISSING_BAD_IMAGE'
  | 'CATEGORY_MISMATCH'
  | 'CONTENT_POLICY'
  | 'UNCLEAR_DESCRIPTION'
  | 'OTHER';

export interface DealDetailData {
  id: string;
  vendorId: string;
  vendorDisplayName: string;
  vendorBusinessName: string;
  dealType: string;
  title: string;
  description: string;
  categoryId: string | null;
  categoryNameHe: string | null;
  categoryNameEn: string | null;
  tags: { id: string; nameHe: string; nameEn: string }[];
  originalPrice: string;
  discountPercent: number;
  discountedPrice: string;
  quantityTotal: number;
  quantitySold: number;
  windowStart: string | null;
  windowEnd: string | null;
  commissionRate: string;
  isPersonalDeal: boolean;
  pickupAddress: string | null;
  specialInstructions: string | null;
  dealState: string;
  rejectionReason: string | null;
  rejectionDetail: string | null;
  appealStatus: string | null;
  appealReason: string | null;
  createdAt: string;
}

export interface LlmJobRow {
  id: string;
  jobType: string;
  status: string;
  decision: string | null;
  flagReason: string | null;
  modelName: string | null;
  totalTokens: number | null;
  createdAt: string;
}

export interface PurchaseRow {
  id: string;
  paymentStatus: string;
  redemptionStatus: string | null;
  amountPaid: string;
  createdAt: string;
  redeemedAt: string | null;
}

export interface ImageRow {
  id: string;
  url: string;
  isPrimary: boolean;
  sortOrder: number;
  approvalStatus: string;
}

export interface ReviewRow {
  id: string;
  rating: number | null;
  body: string;
  reviewType: string;
  isVisible: boolean;
  createdAt: string;
}

export interface DealDetailProps {
  deal: DealDetailData;
  llmJobs: LlmJobRow[];
  purchases: PurchaseRow[];
  images: ImageRow[];
  reviews: ReviewRow[];
  initialLocale: Locale;
}

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

function InfoRow({
  label,
  value,
  labelTooltip,
}: {
  label: string;
  value: React.ReactNode;
  labelTooltip?: string;
}) {
  const labelNode = labelTooltip ? (
    <Tooltip>
      <TooltipTrigger asChild>
        <span className="cursor-help underline decoration-dotted underline-offset-2">{label}</span>
      </TooltipTrigger>
      <TooltipContent side="top" className="max-w-xs text-xs">
        {labelTooltip}
      </TooltipContent>
    </Tooltip>
  ) : (
    label
  );
  return (
    <div className="border-border-default grid grid-cols-2 gap-2 border-b py-2 last:border-0">
      <dt className="text-text-secondary text-sm">{labelNode}</dt>
      <dd className="text-text-primary text-sm font-medium">{value}</dd>
    </div>
  );
}

function SectionCard({ title, children }: { title?: string; children: React.ReactNode }) {
  return (
    <div className="bg-surface-default rounded-2xl p-4 shadow-md">
      {title && <h3 className="text-2xl font-[var(--font-weight-extrabold)]">{title}</h3>}
      {children}
    </div>
  );
}

const STATE_TONE: Record<string, 'success' | 'warning' | 'danger' | 'neutral' | 'info'> = {
  ACTIVE: 'success',
  PENDING_APPROVAL: 'warning',
  UNDER_REVIEW: 'info',
  DRAFT: 'neutral',
  PAUSED: 'neutral',
  SOLD_OUT: 'neutral',
  EXPIRED: 'neutral',
  REJECTED: 'danger',
};

const PAYMENT_TONE: Record<string, 'success' | 'warning' | 'danger' | 'neutral' | 'info'> = {
  COMPLETED: 'success',
  PENDING: 'warning',
  REFUND_REQUESTED: 'info',
  REFUNDED: 'danger',
  PARTIAL_REFUND: 'danger',
};

const REDEMPTION_TONE: Record<string, 'success' | 'warning' | 'danger' | 'neutral' | 'info'> = {
  REDEEMED: 'success',
  UNREDEEMED: 'info',
  CANCELLED: 'danger',
  EXPIRED: 'neutral',
};

const APPROVAL_TONE: Record<string, 'success' | 'warning' | 'danger' | 'neutral' | 'info'> = {
  APPROVED: 'success',
  PENDING: 'warning',
  REJECTED: 'danger',
};

const APPEAL_TONE: Record<string, 'success' | 'warning' | 'danger' | 'neutral' | 'info'> = {
  PENDING: 'warning',
  ACCEPTED: 'success',
  REJECTED: 'danger',
};

const REJECTION_REASON_KEYS: Record<string, string> = {
  WRONG_PRICE: 'reject_reason_wrong_price',
  MISSING_BAD_IMAGE: 'reject_reason_missing_image',
  CATEGORY_MISMATCH: 'reject_reason_category_mismatch',
  CONTENT_POLICY: 'reject_reason_content_policy',
  UNCLEAR_DESCRIPTION: 'reject_reason_unclear_description',
  OTHER: 'reject_reason_other',
};

const LLM_DECISION_KEYS: Record<string, string> = {
  APPROVE: 'llm_decision_approve',
  FLAG: 'llm_decision_flag',
  REJECT: 'llm_decision_reject',
};

function rejectionReasonLabel(reason: string, tAdmin: (key: string) => string): string {
  const key = REJECTION_REASON_KEYS[reason];
  return key ? tAdmin(key) : reason;
}

function llmDecisionLabel(decision: string, tAdmin: (key: string) => string): string {
  const key = LLM_DECISION_KEYS[decision];
  return key ? tAdmin(key) : decision;
}

function jobTypeLabel(jobType: string, t: (key: string) => string): string {
  return t(`job_type_${jobType}`) || jobType;
}

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

export function DealDetail({ initialLocale, ...props }: DealDetailProps) {
  return (
    <LocaleProvider locale={initialLocale}>
      <DealDetailInner {...props} />
    </LocaleProvider>
  );
}

function DealDetailInner({
  deal: initialDeal,
  llmJobs,
  purchases,
  images,
  reviews,
}: Omit<DealDetailProps, 'initialLocale'>) {
  const t = useT('admin_deal_detail');
  const tAdmin = useT('admin');
  const tCommon = useT('common');
  const { locale } = useLocale();

  const [deal, setDeal] = useState<DealDetailData>(initialDeal);
  const [loading, setLoading] = useState<string | null>(null);
  const [actionError, setActionError] = useState<string | null>(null);

  // Category & Tags
  const [availableCategories, setAvailableCategories] = useState<
    { id: string; nameHe: string; nameEn: string }[]
  >([]);
  const [availableTags, setAvailableTags] = useState<
    { id: string; nameHe: string; nameEn: string }[]
  >([]);
  const [selectedCategoryId, setSelectedCategoryId] = useState<string | null>(
    initialDeal.categoryId,
  );
  const [selectedTagIds, setSelectedTagIds] = useState<string[]>(initialDeal.tags.map((t) => t.id));
  const [categoryError, setCategoryError] = useState<string | null>(null);

  useEffect(() => {
    fetch(`/api/admin/categories?dealType=${deal.dealType}`)
      .then(
        (r) =>
          r.json() as Promise<{ categories: { id: string; nameHe: string; nameEn: string }[] }>,
      )
      .then((data) => {
        setAvailableCategories(data.categories ?? []);
      })
      .catch((err) => {
        captureCaught(err, { scope: 'features.admin-deal-detail.DealDetail', severity: 'info' });
      });
  }, [deal.dealType]);

  // Fetch all active tags once at mount — tags are no longer filtered by category.
  useEffect(() => {
    fetch('/api/admin/tags')
      .then((r) => r.json() as Promise<{ tags: { id: string; nameHe: string; nameEn: string }[] }>)
      .then((data) => {
        setAvailableTags(data.tags ?? []);
      })
      .catch((err) => {
        captureCaught(err, { scope: 'features.admin-deal-detail.DealDetail', severity: 'info' });
      });
  }, []);

  async function saveCategoryAssignment() {
    setCategoryError(null);
    setLoading('category');
    try {
      const res = await fetch(`/api/admin/deals/${deal.id}/category`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json', 'x-csrf-token': getCsrfToken() },
        body: JSON.stringify({ categoryId: selectedCategoryId, tagIds: selectedTagIds }),
      });
      if (!res.ok) {
        const err = (await res.json().catch((err) => {
          captureCaught(err, {
            scope: 'features.admin-deal-detail.DealDetail',
            severity: 'warning',
          });
          return { error: 'Unknown error' };
        })) as {
          error?: string;
        };
        throw new Error(err.error ?? 'Unknown error');
      }
      const cat = availableCategories.find((c) => c.id === selectedCategoryId) ?? null;
      const tags = availableTags.filter((tg) => selectedTagIds.includes(tg.id));
      setDeal((prev) => ({
        ...prev,
        categoryId: selectedCategoryId,
        categoryNameHe: cat?.nameHe ?? null,
        categoryNameEn: cat?.nameEn ?? null,
        tags,
      }));
    } catch (err) {
      setCategoryError(err instanceof Error ? err.message : String(err));
    } finally {
      setLoading(null);
    }
  }

  // Reject dialog
  const [rejectOpen, setRejectOpen] = useState(false);
  const [rejectionReason, setRejectionReason] = useState<RejectionReason | ''>('');
  const [rejectionDetail, setRejectionDetail] = useState('');

  // Approve dialog
  const [approveOpen, setApproveOpen] = useState(false);

  // Force-remount keys for ErrorBoundary retry — bumping resets `hasError`.
  const [rejectRetryKey, setRejectRetryKey] = useState(0);
  const [approveRetryKey, setApproveRetryKey] = useState(0);

  // Anticipatory preload on hover/focus of the trigger buttons.
  const preloadReject = () => {
    void importRejectDialog();
  };
  const preloadApprove = () => {
    void importApproveDialog();
  };

  async function handleApprove() {
    setLoading('approve');
    setActionError(null);
    try {
      const res = await fetch(`/api/admin/deals/${deal.id}/approve`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'x-csrf-token': getCsrfToken() },
        body: JSON.stringify({}),
      });
      if (!res.ok) throw new Error(await res.text());
      setDeal((prev) => ({ ...prev, dealState: 'ACTIVE' }));
    } catch (err) {
      setActionError(err instanceof Error ? err.message : String(err));
    } finally {
      setLoading(null);
    }
  }

  async function handleRejectConfirm() {
    if (!rejectionReason) return;
    setLoading('reject');
    setActionError(null);
    try {
      const res = await fetch(`/api/admin/deals/${deal.id}/reject`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json', 'x-csrf-token': getCsrfToken() },
        body: JSON.stringify({ reason: rejectionReason, detail: rejectionDetail }),
      });
      if (!res.ok) throw new Error(await res.text());
      setDeal((prev) => ({
        ...prev,
        dealState: 'REJECTED',
        rejectionReason,
        rejectionDetail,
      }));
      setRejectOpen(false);
      setRejectionReason('');
      setRejectionDetail('');
    } catch (err) {
      setActionError(err instanceof Error ? err.message : String(err));
    } finally {
      setLoading(null);
    }
  }

  // ── Summary card ──────────────────────────────────────────────────────────
  const summary = (
    <Stack gap="4">
      <div>
        <p className="text-text-primary text-lg font-bold" data-user-displayname>
          {deal.title}
        </p>
        <p className="text-text-secondary mt-1 text-sm" data-user-displayname>
          {deal.vendorDisplayName}
        </p>
        <Row gap="2" className="mt-2">
          <Pill tone={STATE_TONE[deal.dealState] ?? 'neutral'} size="sm">
            {(t as (k: string) => string)(`state_${deal.dealState}`) || deal.dealState}
          </Pill>
          {deal.isPersonalDeal && (
            <Tooltip>
              <TooltipTrigger asChild>
                <span className="inline-flex">
                  <Pill tone="info" size="sm">
                    {t('badge_personal')}
                  </Pill>
                </span>
              </TooltipTrigger>
              <TooltipContent side="top" className="max-w-xs text-xs">
                {t('badge_personal_tooltip')}
              </TooltipContent>
            </Tooltip>
          )}
        </Row>
      </div>

      <dl>
        <InfoRow
          label={t('field_original_price')}
          value={
            <span className="line-through">
              {tCommon('currency_symbol')}
              {Number(deal.originalPrice).toFixed(2)}
            </span>
          }
        />
        <InfoRow
          label={t('field_discounted_price')}
          value={
            <span className="text-brand-primary-700">
              {tCommon('currency_symbol')}
              {Number(deal.discountedPrice).toFixed(2)}
            </span>
          }
        />
        <InfoRow label={t('field_discount_percent')} value={`${deal.discountPercent}%`} />
        <InfoRow
          label={t('field_quantity')}
          value={`${deal.quantitySold} / ${deal.quantityTotal}`}
        />
        <InfoRow
          label={t('field_vendor')}
          value={
            <a
              href={`/admin/vendors/${deal.vendorId}`}
              className="text-brand-primary-700 hover:underline"
              data-user-displayname
            >
              {deal.vendorDisplayName}
            </a>
          }
        />
        <InfoRow label={t('field_created')} value={formatDate(deal.createdAt, locale)} />
      </dl>

      {/* Actions */}
      {(deal.dealState === 'PENDING_APPROVAL' || deal.dealState === 'UNDER_REVIEW') && (
        <Stack gap="2">
          {actionError && (
            <p role="alert" className="text-danger-600 text-sm">
              {actionError}
            </p>
          )}
          <Button
            variant="primary"
            size="sm"
            disabled={loading !== null}
            onClick={() => setApproveOpen(true)}
            onMouseEnter={preloadApprove}
            onFocus={preloadApprove}
            data-testid="approve-trigger"
          >
            {t('action_approve_deal')}
          </Button>

          <Button
            variant="danger"
            size="sm"
            disabled={loading !== null}
            onClick={() => setRejectOpen(true)}
            onMouseEnter={preloadReject}
            onFocus={preloadReject}
            data-testid="reject-trigger"
          >
            {t('action_reject_deal')}
          </Button>
        </Stack>
      )}
    </Stack>
  );

  // ── Overview tab ──────────────────────────────────────────────────────────
  const overviewTab = (
    <Stack gap="4">
      <SectionCard title={t('section_details')}>
        <dl>
          <InfoRow
            label={t('field_deal_type')}
            value={(t as (k: string) => string)(`deal_type_${deal.dealType}`) || deal.dealType}
          />
          <InfoRow
            label={t('field_description')}
            value={
              <p className="text-text-primary text-sm" data-user-displayname>
                {deal.description}
              </p>
            }
          />
          {deal.pickupAddress && (
            <InfoRow label={t('field_pickup_address')} value={deal.pickupAddress} />
          )}
          {deal.specialInstructions && (
            <InfoRow label={t('field_special_instructions')} value={deal.specialInstructions} />
          )}
          <InfoRow
            label={t('field_window')}
            labelTooltip={t('field_window_tooltip')}
            value={
              deal.windowStart
                ? `${formatDate(deal.windowStart, locale)} – ${deal.windowEnd ? formatDate(deal.windowEnd, locale) : '—'}`
                : '—'
            }
          />
          <InfoRow
            label={t('field_commission')}
            labelTooltip={t('field_commission_tooltip')}
            value={`${(parseFloat(deal.commissionRate) * 100).toFixed(0)}%`}
          />
          {deal.rejectionReason && (
            <InfoRow
              label={t('field_rejection_reason')}
              value={
                <span className="text-danger-700 text-sm">
                  {rejectionReasonLabel(deal.rejectionReason, tAdmin as (key: string) => string)}
                </span>
              }
            />
          )}
          {deal.rejectionDetail && (
            <InfoRow
              label={t('field_rejection_detail')}
              value={<span className="text-text-secondary text-sm">{deal.rejectionDetail}</span>}
            />
          )}
          {deal.appealStatus && deal.appealStatus !== 'NONE' && (
            <InfoRow
              label={t('field_appeal_status')}
              value={
                <Pill tone={APPEAL_TONE[deal.appealStatus] ?? 'neutral'} size="sm">
                  {(t as (k: string) => string)(`appeal_${deal.appealStatus}`) || deal.appealStatus}
                </Pill>
              }
            />
          )}
          {deal.appealReason && (
            <InfoRow label={t('field_appeal_reason')} value={deal.appealReason} />
          )}
        </dl>
      </SectionCard>

      <SectionCard title={t('section_category')}>
        <Stack gap="3">
          <div>
            <p className="text-text-secondary mb-2 text-sm">{t('field_category')}</p>
            <CategoryPillGroup
              categories={availableCategories}
              selected={selectedCategoryId}
              onSelect={(id) => {
                setSelectedCategoryId(id);
                setSelectedTagIds([]);
              }}
              locale={locale === 'en' ? 'en' : 'he'}
            />
          </div>
          {selectedCategoryId && availableTags.length > 0 && (
            <div>
              <p className="text-text-secondary mb-2 text-sm">{t('field_tags')}</p>
              <TagPillGroup
                tags={availableTags}
                selected={selectedTagIds}
                onToggle={(id) =>
                  setSelectedTagIds((prev) =>
                    prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id],
                  )
                }
                locale={locale === 'en' ? 'en' : 'he'}
                label={t('field_tags')}
              />
            </div>
          )}
          {categoryError && (
            <p role="alert" className="text-danger-600 text-sm">
              {categoryError}
            </p>
          )}
          <Button
            variant="primary"
            size="sm"
            disabled={loading !== null}
            onClick={saveCategoryAssignment}
          >
            {t('edit_category')}
          </Button>
        </Stack>
      </SectionCard>
    </Stack>
  );

  // ── Moderation tab ────────────────────────────────────────────────────────
  const moderationTab = (
    <Stack gap="4">
      {llmJobs.length === 0 ? (
        <SectionCard>
          <p className="text-text-secondary py-4 text-center text-sm">{t('moderation_empty')}</p>
        </SectionCard>
      ) : (
        <SectionCard title={t('section_llm_jobs')}>
          <AdminTable
            columns={[
              {
                key: 'jobType',
                label: t('llm_col_job_type'),
                render: (job) => jobTypeLabel(job.jobType, t as (k: string) => string),
              },
              {
                key: 'status',
                label: t('llm_col_status'),
                render: (job) => (
                  <Pill
                    tone={
                      job.status === 'COMPLETED'
                        ? 'success'
                        : job.status === 'FAILED' || job.status === 'TIMED_OUT'
                          ? 'danger'
                          : job.status === 'RUNNING'
                            ? 'info'
                            : 'neutral'
                    }
                    size="sm"
                  >
                    {(t as (k: string) => string)(`job_status_${job.status}`) || job.status}
                  </Pill>
                ),
              },
              {
                key: 'decision',
                label: t('llm_col_decision'),
                render: (job) => {
                  if (!job.decision) return '—';
                  const pill = (
                    <Pill
                      tone={
                        job.decision === 'APPROVE'
                          ? 'success'
                          : job.decision === 'FLAG'
                            ? 'warning'
                            : 'danger'
                      }
                      size="sm"
                    >
                      {llmDecisionLabel(job.decision, tAdmin as (key: string) => string)}
                    </Pill>
                  );
                  if (job.decision !== 'FLAG') return pill;
                  return (
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <span className="inline-flex">{pill}</span>
                      </TooltipTrigger>
                      <TooltipContent side="top" className="max-w-xs text-xs">
                        {t('decision_flag_tooltip')}
                      </TooltipContent>
                    </Tooltip>
                  );
                },
              },
              {
                key: 'modelName',
                label: t('llm_col_model'),
                render: (job) => (
                  <span className="text-text-secondary text-xs">{job.modelName ?? '—'}</span>
                ),
              },
              {
                key: 'createdAt',
                label: t('llm_col_created'),
                render: (job) => (
                  <span className="text-text-secondary text-xs">
                    {formatDate(job.createdAt, locale)}
                  </span>
                ),
              },
            ]}
            rows={llmJobs}
          />
          {llmJobs.some((j) => j.flagReason) && (
            <Stack gap="2" className="mt-4">
              {llmJobs
                .filter((j) => j.flagReason)
                .map((j) => (
                  <div
                    key={j.id}
                    className="border-warning-200 bg-warning-50 text-warning-800 rounded-md border p-3 text-xs"
                  >
                    <span className="font-semibold">
                      {t('flag_reason_prefix')} (
                      {jobTypeLabel(j.jobType, t as (k: string) => string)}):{' '}
                    </span>
                    {j.flagReason}
                  </div>
                ))}
            </Stack>
          )}
        </SectionCard>
      )}
    </Stack>
  );

  // ── Purchases tab ─────────────────────────────────────────────────────────
  const purchasesTab = (
    <Stack gap="4">
      {purchases.length === 0 ? (
        <SectionCard>
          <p className="text-text-secondary py-4 text-center text-sm">{t('purchases_empty')}</p>
        </SectionCard>
      ) : (
        <SectionCard title={t('section_purchases')}>
          <AdminTable
            columns={[
              {
                key: 'createdAt',
                label: t('purchase_col_date'),
                render: (p) => formatDate(p.createdAt, locale),
              },
              {
                key: 'amountPaid',
                label: t('purchase_col_amount'),
                render: (p) => `${tCommon('currency_symbol')}${Number(p.amountPaid).toFixed(2)}`,
              },
              {
                key: 'paymentStatus',
                label: t('purchase_col_payment'),
                render: (p) => (
                  <Pill tone={PAYMENT_TONE[p.paymentStatus] ?? 'neutral'} size="sm">
                    {(t as (k: string) => string)(`payment_${p.paymentStatus}`) || p.paymentStatus}
                  </Pill>
                ),
              },
              {
                key: 'redemptionStatus',
                label: t('purchase_col_redemption'),
                render: (p) => (
                  <Pill tone={REDEMPTION_TONE[p.redemptionStatus ?? ''] ?? 'neutral'} size="sm">
                    {(t as (k: string) => string)(`redemption_${p.redemptionStatus}`) ||
                      p.redemptionStatus}
                  </Pill>
                ),
              },
            ]}
            rows={purchases}
            rowHref={(p) => `/admin/purchases/${p.id}`}
          />
        </SectionCard>
      )}
    </Stack>
  );

  // ── Images tab ────────────────────────────────────────────────────────────
  const imagesTab = (
    <Stack gap="4">
      {images.length === 0 ? (
        <SectionCard>
          <p className="text-text-secondary py-4 text-center text-sm">{t('images_empty')}</p>
        </SectionCard>
      ) : (
        <SectionCard title={t('section_images')}>
          <div className="grid grid-cols-2 gap-3 sm:grid-cols-3 md:grid-cols-4">
            {images.map((img) => (
              <div
                key={img.id}
                className="bg-surface-default flex flex-col gap-2 rounded-2xl p-2 shadow-md"
              >
                <Image
                  src={img.url}
                  alt=""
                  decorative
                  width={120}
                  height={120}
                  className="aspect-square w-full rounded-md"
                  loading="lazy"
                />
                <Row gap="1" wrap>
                  {img.isPrimary && (
                    <Tooltip>
                      <TooltipTrigger asChild>
                        <span className="inline-flex">
                          <Pill tone="info" size="sm">
                            {t('image_primary')}
                          </Pill>
                        </span>
                      </TooltipTrigger>
                      <TooltipContent side="top" className="max-w-xs text-xs">
                        {t('image_primary_tooltip')}
                      </TooltipContent>
                    </Tooltip>
                  )}
                  <Pill tone={APPROVAL_TONE[img.approvalStatus] ?? 'neutral'} size="sm">
                    {(t as (k: string) => string)(`approval_${img.approvalStatus}`) ||
                      img.approvalStatus}
                  </Pill>
                </Row>
              </div>
            ))}
          </div>
        </SectionCard>
      )}
    </Stack>
  );

  // ── Reviews tab ───────────────────────────────────────────────────────────
  const reviewsTab = (
    <Stack gap="4">
      {reviews.length === 0 ? (
        <SectionCard>
          <p className="text-text-secondary py-4 text-center text-sm">{t('reviews_empty')}</p>
        </SectionCard>
      ) : (
        <SectionCard title={t('section_reviews')}>
          <Stack gap="3" as="ul">
            {reviews.map((review) => (
              <li
                key={review.id}
                className="border-border-default border-b pb-3 last:border-0 last:pb-0"
              >
                <Row justify="between" align="start">
                  <Stack gap="1" className="min-w-0 flex-1">
                    {review.rating !== null && (
                      <p className="text-sm" aria-label={`${t('tab_reviews')}: ${review.rating}/5`}>
                        <span aria-hidden="true">{'⭐'.repeat(review.rating)}</span>
                        <span className="text-text-secondary ms-1 text-xs">
                          ({review.rating}/5)
                        </span>
                      </p>
                    )}
                    <p className="text-text-primary line-clamp-3 text-sm">{review.body}</p>
                    <Row gap="2">
                      <span className="text-text-secondary text-xs">
                        {formatDate(review.createdAt, locale)}
                      </span>
                      {!review.isVisible && (
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <span className="inline-flex">
                              <Pill tone="danger" size="sm">
                                {t('review_hidden')}
                              </Pill>
                            </span>
                          </TooltipTrigger>
                          <TooltipContent side="top" className="max-w-xs text-xs">
                            {t('review_hidden_tooltip')}
                          </TooltipContent>
                        </Tooltip>
                      )}
                      {review.reviewType === 'TECHNICAL' && (
                        <Tooltip>
                          <TooltipTrigger asChild>
                            <span className="inline-flex">
                              <Pill tone="neutral" size="sm">
                                {t('review_technical')}
                              </Pill>
                            </span>
                          </TooltipTrigger>
                          <TooltipContent side="top" className="max-w-xs text-xs">
                            {t('review_technical_tooltip')}
                          </TooltipContent>
                        </Tooltip>
                      )}
                    </Row>
                  </Stack>
                </Row>
              </li>
            ))}
          </Stack>
        </SectionCard>
      )}
    </Stack>
  );

  // ── Tabs ──────────────────────────────────────────────────────────────────
  const tabs = [
    { key: 'overview', label: t('tab_overview'), content: overviewTab },
    { key: 'moderation', label: t('tab_moderation'), content: moderationTab },
    { key: 'purchases', label: t('tab_purchases'), content: purchasesTab },
    { key: 'images', label: t('tab_images'), content: imagesTab },
    { key: 'reviews', label: t('tab_reviews'), content: reviewsTab },
  ];

  // ── Lazy moderation dialogs ───────────────────────────────────────────────
  const rejectDialog = rejectOpen ? (
    <ErrorBoundary
      key={`reject-${rejectRetryKey}`}
      fallback={
        <RetryPanel
          variant="card"
          onRetry={() => {
            void importRejectDialog();
            setRejectRetryKey((k) => k + 1);
          }}
        />
      }
    >
      <Suspense fallback={<DialogSkeleton />}>
        <RejectDialogLazy
          dealTitle={deal.title}
          reason={rejectionReason}
          detail={rejectionDetail}
          loading={loading === 'reject'}
          actionError={actionError}
          onReasonChange={setRejectionReason}
          onDetailChange={setRejectionDetail}
          onConfirm={handleRejectConfirm}
          onCancel={() => setRejectOpen(false)}
        />
      </Suspense>
    </ErrorBoundary>
  ) : null;

  const approveDialog = approveOpen ? (
    <ErrorBoundary
      key={`approve-${approveRetryKey}`}
      fallback={
        <RetryPanel
          variant="card"
          onRetry={() => {
            void importApproveDialog();
            setApproveRetryKey((k) => k + 1);
          }}
        />
      }
    >
      <Suspense fallback={null}>
        <ApproveDialogLazy
          open={approveOpen}
          onOpenChange={setApproveOpen}
          onConfirm={handleApprove}
        />
      </Suspense>
    </ErrorBoundary>
  ) : null;

  return (
    <TooltipProvider delayDuration={150}>
      {rejectDialog}
      {approveDialog}
      <AdminDetailPage summary={summary} tabs={tabs} defaultTab="overview" />
    </TooltipProvider>
  );
}
