// src/features/admin-images/ImageModeration.tsx
// Admin: image moderation queue - review, approve, and reject uploaded images.

'use client';

import { useState, useEffect, startTransition } from 'react';
import { getCsrfToken } from '@/lib/csrf';
import { formatBytes, formatDateTime } from '@/lib/format';
import { useT, useLocale } from '@/lib/i18n/react';
import { interpolate } from '@/lib/i18n/interpolate';
import { usePaginatedQuery } from '@/lib/hooks/usePaginatedQuery';
import { Button } from '@/components/ui/primitives/Button';
import { Stack } from '@/components/ui/layout/Stack';
import { Row } from '@/components/ui/layout/Row';
import { Pagination } from '@/components/ui/primitives/Pagination';
import { Image } from '@/components/ui/primitives/Image';
import { buildVariantUrl } from '@/components/ui/primitives/Image/buildVariantUrl';
import { Tabs } from '@/components/ui/layout/Tabs/Tabs';
import {
  Select,
  SelectTrigger,
  SelectValue,
  SelectContent,
  SelectItem,
} from '@/components/ui/primitives/Select';
import { Label } from '@/components/ui/primitives/Label';
import { Badge } from '@/components/ui/primitives/Badge';
import { cn } from '@/lib/cn';
import { ErrorBoundary } from '@/components/ui/feedback/ErrorBoundary';
import {
  AlertDialog,
  AlertDialogContent,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogAction,
  AlertDialogCancel,
} from '@/components/ui/overlays/AlertDialog';
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/overlays/Tooltip';
import { captureCaught } from '@/lib/observability';
import { type ScanStatus } from '@/lib/enums/scan-status';

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

export type { ScanStatus };
export type ImageApprovalStatus = 'PENDING' | 'APPROVED' | 'REJECTED';

export interface ImageRow {
  id: string;
  r2Key: string;
  mime: string;
  sizeBytes: number;
  scanStatus: ScanStatus;
  approvalStatus: ImageApprovalStatus;
  uploaderUserId: string | null;
  uploaderVendorId: string | null;
  uploaderUserName?: string | null;
  uploaderVendorName?: string | null;
  createdAt: string;
}

export interface ImageModerationProps {
  initialImages: ImageRow[];
  initialTotal: number;
  initialPage?: number;
  /** Deep-link from approval queue: /admin/moderation/images?imageId=… */
  focusImageId?: string | null;
}

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

function rejectReasonLabel(code: string, t: (key: string) => string): string {
  const key = `reject_reason_${code.toLowerCase()}` as const;
  const translated = t(key);
  if (translated !== key) return translated;
  return interpolate(t('reject_reason_fallback'), { code });
}

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

export function ImageModeration({
  initialImages,
  initialTotal,
  initialPage,
  focusImageId = null,
}: ImageModerationProps) {
  const t = useT('admin_images');

  const [scanStatusFilter, setScanStatusFilter] = useState<ScanStatus | ''>('');
  const [approvalStatusFilter, setApprovalStatusFilter] = useState<ImageApprovalStatus | ''>(
    'PENDING',
  );
  const [actionLoading, setActionLoading] = useState<string | null>(null);
  const [actionError, setActionError] = useState<string | null>(null);

  const filterParams: Record<string, string> = {};
  if (scanStatusFilter) filterParams.scanStatus = scanStatusFilter;
  if (approvalStatusFilter) filterParams.approvalStatus = approvalStatusFilter;

  const {
    data: images,
    total,
    totalPages,
    page,
    isLoading,
    error,
    setPage,
    refetch,
  } = usePaginatedQuery<ImageRow>({
    endpoint: '/api/admin/images',
    params: filterParams,
    limit: 20,
    initialData: initialImages,
    initialTotal,
    initialPage,
    dataKey: 'images',
  });

  async function handleApprove(imageId: string) {
    setActionLoading(imageId);
    setActionError(null);
    try {
      const res = await fetch(`/api/admin/images/${imageId}/approve`, {
        method: 'POST',
        headers: { 'x-csrf-token': getCsrfToken() },
      });
      if (!res.ok) {
        const body = (await res.json().catch((err) => {
          captureCaught(err, { scope: 'features.admin-images.ImageModeration', severity: 'info' });
          return {};
        })) as Record<string, unknown>;
        throw new Error((body.error as string) || `HTTP ${res.status}`);
      }
      refetch();
    } catch (err) {
      setActionError(err instanceof Error ? err.message : String(err));
    } finally {
      setActionLoading(null);
    }
  }

  async function handleReject(imageId: string) {
    setActionLoading(imageId);
    setActionError(null);
    try {
      const res = await fetch(`/api/admin/images/${imageId}/reject`, {
        method: 'POST',
        headers: { 'x-csrf-token': getCsrfToken() },
      });
      if (!res.ok) {
        const body = (await res.json().catch((err) => {
          captureCaught(err, { scope: 'features.admin-images.ImageModeration', severity: 'info' });
          return {};
        })) as Record<string, unknown>;
        throw new Error((body.error as string) || `HTTP ${res.status}`);
      }
      refetch();
    } catch (err) {
      setActionError(err instanceof Error ? err.message : String(err));
    } finally {
      setActionLoading(null);
    }
  }

  const displayError = actionError ?? error;
  const hasFilters = Boolean(scanStatusFilter || approvalStatusFilter);

  useEffect(() => {
    if (!focusImageId || typeof document === 'undefined') return;
    const el = document.getElementById(`image-card-${focusImageId}`);
    el?.scrollIntoView({ behavior: 'smooth', block: 'center' });
    el?.classList.add('ring-brand-primary-500', 'ring-2');
  }, [focusImageId, images]);

  const imagesPanel = (
    <Stack gap="6" className="pt-6">
      {/* Filters */}
      <Row gap="4" wrap>
        <div className="min-w-40">
          <Label htmlFor="filter-scan">{t('filter_scan_status')}</Label>
          <Select
            value={scanStatusFilter || '__all__'}
            onValueChange={(v) =>
              setScanStatusFilter((v === '__all__' ? '' : v) as ScanStatus | '')
            }
          >
            <SelectTrigger id="filter-scan">
              <SelectValue placeholder={t('filter_all')} />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="__all__">{t('filter_all')}</SelectItem>
              <SelectItem value="PENDING">{t('scan_pending')}</SelectItem>
              <SelectItem value="CLEAN">{t('scan_clean')}</SelectItem>
              <SelectItem value="INFECTED">{t('scan_infected')}</SelectItem>
              <SelectItem value="ERROR">{t('scan_error')}</SelectItem>
            </SelectContent>
          </Select>
        </div>

        <div className="min-w-44">
          <Label htmlFor="filter-approval">{t('filter_approval_status')}</Label>
          <Select
            value={approvalStatusFilter || '__all__'}
            onValueChange={(v) =>
              setApprovalStatusFilter((v === '__all__' ? '' : v) as ImageApprovalStatus | '')
            }
          >
            <SelectTrigger id="filter-approval">
              <SelectValue placeholder={t('filter_all')} />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="__all__">{t('filter_all')}</SelectItem>
              <SelectItem value="PENDING">{t('approval_pending')}</SelectItem>
              <SelectItem value="APPROVED">{t('approval_approved')}</SelectItem>
              <SelectItem value="REJECTED">{t('approval_rejected')}</SelectItem>
            </SelectContent>
          </Select>
        </div>
      </Row>

      {/* Error */}
      {displayError && (
        <p role="alert" className="text-danger-600 text-sm">
          {displayError}
        </p>
      )}

      {/* Grid */}
      {isLoading ? (
        <p className="text-text-secondary py-8 text-center text-sm">{t('images_loading')}</p>
      ) : images.length === 0 ? (
        <p className="text-text-secondary py-8 text-center text-sm">
          {hasFilters ? t('no_images_filtered') : t('no_images')}
        </p>
      ) : (
        <ul
          className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3"
          aria-label={t('title')}
        >
          {images.map((image) => (
            <ImageCard
              key={image.id}
              id={`image-card-${image.id}`}
              image={image}
              actionLoading={actionLoading === image.id}
              onApprove={() => handleApprove(image.id)}
              onReject={() => handleReject(image.id)}
              thumbUrl={buildVariantUrl(`/r2/${image.r2Key}`, 'thumb', 240) ?? `/r2/${image.r2Key}`}
              highlighted={focusImageId === image.id}
            />
          ))}
        </ul>
      )}

      {/* Pagination */}
      <Pagination
        page={page}
        totalPages={totalPages}
        onPageChange={setPage}
        isLoading={isLoading}
      />

      {/* Total count */}
      {total > 0 && (
        <p className="text-text-secondary text-center text-xs">
          {interpolate(t('total_count'), { count: total })}
        </p>
      )}
    </Stack>
  );

  return (
    <ErrorBoundary>
      <Stack gap="6" as="section" aria-label={t('title')}>
        <Tabs
          items={[
            { value: 'images', label: t('tab_images') },
            { value: 'vendor-hero', label: t('tab_vendor_hero') },
          ]}
          defaultValue="images"
          panels={{
            images: imagesPanel,
            'vendor-hero': (
              <div className="pt-6">
                <VendorHeroModeration />
              </div>
            ),
          }}
        />
      </Stack>
    </ErrorBoundary>
  );
}

// ─── ImageCard sub-component ──────────────────────────────────────────────────

interface ImageCardProps {
  id?: string;
  image: ImageRow;
  actionLoading: boolean;
  onApprove: () => void;
  onReject: () => void;
  thumbUrl: string;
  highlighted?: boolean;
}

function ImageCard({
  id,
  image,
  actionLoading,
  onApprove,
  onReject,
  thumbUrl,
  highlighted = false,
}: ImageCardProps) {
  const t = useT('admin_images');
  const tCommon = useT('common');
  const { locale } = useLocale();
  const [approveOpen, setApproveOpen] = useState(false);
  const [rejectOpen, setRejectOpen] = useState(false);

  const uploaderAlt =
    image.uploaderUserName ??
    image.uploaderVendorName ??
    (image.uploaderUserId || image.uploaderVendorId ? t('uploader_unknown') : t('title'));

  const isInfected = image.scanStatus === 'INFECTED';
  const isPendingScan = image.scanStatus === 'PENDING';
  const approveBlocked = isInfected || isPendingScan;
  const approveDisabledTooltip = isInfected
    ? t('approve_disabled_infected')
    : isPendingScan
      ? t('approve_disabled_pending_scan')
      : undefined;

  return (
    <li
      id={id}
      className={cn(
        'bg-surface-default flex flex-col gap-3 rounded-2xl p-4 shadow-md',
        isInfected ? 'ring-danger-400 ring-2' : '',
        highlighted ? 'ring-brand-primary-500 ring-2' : '',
      )}
    >
      {/* Thumbnail */}
      <div className="bg-surface-inset relative overflow-hidden rounded-md">
        <Image
          raw
          src={thumbUrl}
          alt={interpolate(t('image_alt_review'), { uploader: uploaderAlt })}
          variant="thumb"
          width={80}
          height={80}
          loading="lazy"
          className="h-20 w-full"
          onError={(e) => {
            const el = e.currentTarget as HTMLImageElement;
            el.onerror = null;
            el.src =
              'data:image/svg+xml,%3Csvg xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22 width%3D%2240%22 height%3D%2240%22%3E%3Crect width%3D%2240%22 height%3D%2240%22 fill%3D%22%23e5e7eb%22%2F%3E%3C%2Fsvg%3E';
          }}
        />
        {isInfected && (
          <span className="bg-danger-50/80 text-danger-700 absolute inset-0 flex items-center justify-center text-xs font-bold">
            {t('scan_infected')}
          </span>
        )}
      </div>

      {/* Badges */}
      <Row gap="2" wrap>
        <ScanBadge status={image.scanStatus} />
        <ApprovalBadge status={image.approvalStatus} />
      </Row>

      {/* Meta */}
      <dl className="text-text-secondary space-y-1 text-xs">
        <div className="flex gap-1">
          <dt className="font-medium">{t('mime_label')}:</dt>
          <dd data-diag="">{image.mime}</dd>
        </div>
        <div className="flex gap-1">
          <dt className="font-medium">{t('size_label')}:</dt>
          <dd data-diag="">{formatBytes(image.sizeBytes)}</dd>
        </div>
        <div className="flex gap-1">
          <dt className="font-medium">{t('uploaded_label')}:</dt>
          <dd>{formatDateTime(image.createdAt, locale)}</dd>
        </div>
        {image.uploaderUserId && (
          <div className="flex gap-1">
            <dt className="font-medium">{t('uploader_user')}:</dt>
            <dd className="truncate" data-diag="">
              <a
                href={`/admin/users/${image.uploaderUserId}`}
                className="text-brand-primary-600 hover:underline"
                title={image.uploaderUserId}
              >
                {image.uploaderUserName ?? image.uploaderUserId.slice(0, 8) + '…'}
              </a>
            </dd>
          </div>
        )}
        {image.uploaderVendorId && (
          <div className="flex gap-1">
            <dt className="font-medium">{t('uploader_vendor')}:</dt>
            <dd className="truncate" data-diag="">
              <a
                href={`/admin/vendors/${image.uploaderVendorId}`}
                className="text-brand-primary-600 hover:underline"
                title={image.uploaderVendorId}
              >
                {image.uploaderVendorName ?? image.uploaderVendorId.slice(0, 8) + '…'}
              </a>
            </dd>
          </div>
        )}
        {!image.uploaderUserId && !image.uploaderVendorId && (
          <div className="flex gap-1">
            <dt className="font-medium">{t('uploader_unknown')}:</dt>
            <dd>-</dd>
          </div>
        )}
      </dl>

      {/* Actions */}
      <Row gap="2">
        <TooltipProvider>
          <Tooltip>
            <TooltipTrigger asChild>
              <span className="inline-flex">
                <Button
                  variant="primary"
                  size="sm"
                  loading={actionLoading}
                  onClick={() => setApproveOpen(true)}
                  disabled={image.approvalStatus === 'APPROVED' || approveBlocked}
                >
                  {t('approve')}
                </Button>
              </span>
            </TooltipTrigger>
            {approveDisabledTooltip ? (
              <TooltipContent>{approveDisabledTooltip}</TooltipContent>
            ) : null}
          </Tooltip>
        </TooltipProvider>
        <Button
          variant="danger"
          size="sm"
          disabled={actionLoading || image.approvalStatus === 'REJECTED'}
          onClick={() => setRejectOpen(true)}
        >
          {t('reject')}
        </Button>
      </Row>

      <AlertDialog open={rejectOpen} onOpenChange={setRejectOpen}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>{t('reject_confirm_title')}</AlertDialogTitle>
            <AlertDialogDescription>{t('reject_confirm_body')}</AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>{tCommon('cancel')}</AlertDialogCancel>
            <AlertDialogAction
              onClick={() => {
                onReject();
                setRejectOpen(false);
              }}
            >
              {t('reject')}
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>

      <AlertDialog open={approveOpen} onOpenChange={setApproveOpen}>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>{t('approve_confirm_title')}</AlertDialogTitle>
            <AlertDialogDescription>{t('approve_confirm_body')}</AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>{tCommon('cancel')}</AlertDialogCancel>
            <AlertDialogAction
              onClick={() => {
                onApprove();
                setApproveOpen(false);
              }}
            >
              {t('approve')}
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </li>
  );
}

// ─── VendorHeroModeration section ─────────────────────────────────────────────

interface VendorHeroRow {
  vendorId: string;
  displayName: string;
  heroPendingImageUrl: string | null;
  heroImageApprovalStatus: string;
  heroImageRejectReasonCode: string | null;
}

/** Extract r2Key from a hero image URL (strips legacy /webp/ prefix if present). */
function r2KeyFromHeroUrl(url: string): string {
  const idx = url.indexOf('/webp/');
  return idx >= 0 ? url.slice(idx + 6) : url;
}

export function VendorHeroModeration() {
  const t = useT('admin_images');
  const [items, setItems] = useState<VendorHeroRow[]>([]);
  const [loading, setLoading] = useState(true);
  const [fetchError, setFetchError] = useState<string | null>(null);
  const [actionLoading, setActionLoading] = useState<string | null>(null);
  const [actionError, setActionError] = useState<string | null>(null);

  useEffect(() => {
    let cancelled = false;
    startTransition(() => {
      setLoading(true);
      setFetchError(null);
    });
    fetch('/api/admin/images/vendor-hero-pending')
      .then(async (res) => {
        const body = (await res.json()) as {
          ok: boolean;
          vendors?: VendorHeroRow[];
          error?: string;
        };
        if (!cancelled) {
          if (body.ok && body.vendors) {
            setItems(body.vendors);
          } else {
            setFetchError(body.error ?? `HTTP ${res.status}`);
          }
        }
      })
      .catch((err: unknown) => {
        if (!cancelled) setFetchError(err instanceof Error ? err.message : String(err));
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, []);

  async function handleForceApprove(vendorId: string) {
    setActionLoading(vendorId);
    setActionError(null);
    try {
      const res = await fetch('/api/admin/images/vendor-hero-approve', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-csrf-token': getCsrfToken(),
        },
        body: JSON.stringify({ vendorId, status: 'APPROVED' }),
      });
      if (!res.ok) {
        const body = (await res.json().catch((err) => {
          captureCaught(err, { scope: 'features.admin-images.ImageModeration', severity: 'info' });
          return {};
        })) as Record<string, unknown>;
        throw new Error((body.error as string) || `HTTP ${res.status}`);
      }
      // Optimistic remove
      setItems((prev) => prev.filter((item) => item.vendorId !== vendorId));
    } catch (err) {
      setActionError(err instanceof Error ? err.message : String(err));
    } finally {
      setActionLoading(null);
    }
  }

  return (
    <Stack gap="6" as="section" aria-label={t('vendor_hero_section_label')}>
      {(actionError ?? fetchError) && (
        <p role="alert" className="text-danger-600 text-sm">
          {actionError ?? fetchError}
        </p>
      )}

      {loading ? (
        <p className="text-text-secondary py-8 text-center text-sm">{t('vendor_hero_loading')}</p>
      ) : items.length === 0 ? (
        <p className="text-text-secondary py-8 text-center text-sm">
          {t('no_vendor_hero_pending')}
        </p>
      ) : (
        <ul
          className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3"
          aria-label={t('vendor_hero_pending_label')}
        >
          {items.map((item) => (
            <VendorHeroCard
              key={item.vendorId}
              item={item}
              actionLoading={actionLoading === item.vendorId}
              onForceApprove={() => handleForceApprove(item.vendorId)}
            />
          ))}
        </ul>
      )}
    </Stack>
  );
}

// ─── VendorHeroCard ────────────────────────────────────────────────────────────

interface VendorHeroCardProps {
  item: VendorHeroRow;
  actionLoading: boolean;
  onForceApprove: () => void;
}

function VendorHeroCard({ item, actionLoading, onForceApprove }: VendorHeroCardProps) {
  const t = useT('admin_images');
  const thumbUrl = (() => {
    if (!item.heroPendingImageUrl) return null;
    const key = r2KeyFromHeroUrl(item.heroPendingImageUrl);
    const raw = key.startsWith('/') || /^https?:/.test(key) ? key : `/r2/${key}`;
    return buildVariantUrl(raw, 'hero', 800) ?? raw;
  })();

  const approvalStatus = (item.heroImageApprovalStatus ?? 'PENDING') as ImageApprovalStatus;

  return (
    <li className="bg-surface-default flex flex-col gap-3 rounded-2xl p-4 shadow-md">
      {/* Thumbnail */}
      <div className="bg-surface-inset relative overflow-hidden rounded-md">
        {thumbUrl ? (
          <Image
            raw
            src={thumbUrl}
            alt=""
            decorative
            variant="thumb"
            width={80}
            height={80}
            loading="lazy"
            className="h-20 w-full"
            onError={(e) => {
              const el = e.currentTarget as HTMLImageElement;
              el.onerror = null;
              el.src =
                'data:image/svg+xml,%3Csvg xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22 width%3D%2240%22 height%3D%2240%22%3E%3Crect width%3D%2240%22 height%3D%2240%22 fill%3D%22%23e5e7eb%22%2F%3E%3C%2Fsvg%3E';
            }}
          />
        ) : (
          <div className="h-20 w-full" aria-hidden="true" />
        )}
      </div>

      {/* Name + approval badge */}
      <Row gap="2" wrap>
        <span className="text-text-primary text-sm font-medium">{item.displayName}</span>
        <ApprovalBadge status={approvalStatus} />
      </Row>

      {/* Reject reason */}
      {item.heroImageRejectReasonCode && (
        <p className="text-text-secondary text-xs">
          {rejectReasonLabel(item.heroImageRejectReasonCode, t as (key: string) => string)}
        </p>
      )}

      {/* Actions */}
      <Row gap="2">
        <Button
          variant="primary"
          size="sm"
          loading={actionLoading}
          disabled={!item.heroPendingImageUrl}
          onClick={onForceApprove}
          title={t('force_approve_tooltip')}
        >
          {t('force_approve')}
        </Button>
      </Row>
    </li>
  );
}

// ─── ScanBadge ────────────────────────────────────────────────────────────────

interface ScanBadgeProps {
  status: ScanStatus;
}

function ScanBadge({ status }: ScanBadgeProps) {
  const t = useT('admin_images');

  const label: Record<ScanStatus, string> = {
    PENDING: t('scan_pending'),
    CLEAN: t('scan_clean'),
    INFECTED: t('scan_infected'),
    ERROR: t('scan_error'),
  };

  const tone: Record<ScanStatus, 'neutral' | 'success' | 'danger' | 'warning'> = {
    PENDING: 'neutral',
    CLEAN: 'success',
    INFECTED: 'danger',
    ERROR: 'warning',
  };

  return (
    <Badge tone={tone[status]} size="sm">
      {label[status]}
    </Badge>
  );
}

// ─── ApprovalBadge ────────────────────────────────────────────────────────────

interface ApprovalBadgeProps {
  status: ImageApprovalStatus;
}

function ApprovalBadge({ status }: ApprovalBadgeProps) {
  const t = useT('admin_images');

  const label: Record<ImageApprovalStatus, string> = {
    PENDING: t('approval_pending'),
    APPROVED: t('approval_approved_badge'),
    REJECTED: t('approval_rejected_badge'),
  };

  const tone: Record<ImageApprovalStatus, 'neutral' | 'success' | 'danger' | 'brand'> = {
    PENDING: 'neutral',
    APPROVED: 'success',
    REJECTED: 'danger',
  };

  return (
    <Badge tone={tone[status]} size="sm">
      {label[status]}
    </Badge>
  );
}
