import { useCallback, useEffect, useState } from 'react';
import { Archive, Check, Headphones, Image as ImageIcon, Loader2, RefreshCw, Search, X } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { hostApiFetch } from '@/lib/host-api';
import type { GameAssetReviewAction } from '@/lib/game-asset-selection-message';
import {
  classifyGameAssetReviewLoadFailure,
  isGameAssetReviewResponse,
  type GameAssetCandidate,
  type GameAssetReviewLoadFailure,
  type GameAssetReviewSnapshot,
} from './game-asset-review-recovery';

export type { GameAssetCandidate } from './game-asset-review-recovery';

type GameAssetDecisionDraft = Record<string, GameAssetReviewAction>;

export function GameAssetBrowser(props: {
  invocationId: string;
  candidateIds?: string[];
  onSubmit?: (assets: GameAssetCandidate[], decisions: GameAssetDecisionDraft) => void | Promise<void>;
}) {
  const [assets, setAssets] = useState<GameAssetCandidate[]>([]);
  const [review, setReview] = useState<GameAssetReviewSnapshot | null>(null);
  const [loading, setLoading] = useState(true);
  const [loadFailure, setLoadFailure] = useState<GameAssetReviewLoadFailure | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [previewAsset, setPreviewAsset] = useState<GameAssetCandidate | null>(null);
  const [draftDecisions, setDraftDecisions] = useState<GameAssetDecisionDraft>({});
  const [showSubmitDialog, setShowSubmitDialog] = useState(false);
  const [submitting, setSubmitting] = useState(false);

  const load = useCallback(async () => {
    setLoading(true);
    setLoadFailure(null);
    setError(null);

    const params = new URLSearchParams({ invocationId: props.invocationId });
    if (props.candidateIds?.length) params.set('candidateIds', JSON.stringify(props.candidateIds));
    const path = `/api/files/game-asset-review?${params.toString()}`;

    try {
      for (let attempt = 0; attempt < 2; attempt += 1) {
        try {
          const response = await hostApiFetch<unknown>(path);
          if (!isGameAssetReviewResponse(response)) {
            setLoadFailure('stale');
            return;
          }
          setReview(response.review);
          setAssets(response.assets);
          setDraftDecisions({});
          setShowSubmitDialog(false);
          return;
        } catch (loadError) {
          const failure = classifyGameAssetReviewLoadFailure(loadError);
          if (failure === 'stale' || attempt === 1) {
            setLoadFailure(failure);
            return;
          }
        }
      }
    } finally {
      setLoading(false);
    }
  }, [props.candidateIds, props.invocationId]);

  useEffect(() => {
    void load();
  }, [load]);

  const chooseAction = (assetId: string, action: GameAssetReviewAction) => {
    if (submitting) return;
    setDraftDecisions((current) => ({ ...current, [assetId]: action }));
    setError(null);
  };

  const selectedCount = assets.filter((asset) => Boolean(draftDecisions[asset.id])).length;
  const allAssetsSelected = assets.length > 0 && selectedCount === assets.length;
  const actionLabel = (action: GameAssetReviewAction): string => (
    action === 'approve' ? '纳入开发' : action === 'discard' ? '舍弃' : '重新寻找'
  );

  const submitBatch = async () => {
    if (!review || !allAssetsSelected || submitting) return;
    setSubmitting(true);
    setError(null);
    const decisions = assets.flatMap((asset) => {
      const action = draftDecisions[asset.id];
      return action ? [{ assetId: asset.id, action }] : [];
    });
    try {
      const response = await hostApiFetch<{ success: boolean; review: GameAssetReviewSnapshot }>('/api/files/game-asset-review', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          invocationId: props.invocationId,
          candidateIds: review.candidateIds,
          decisions,
        }),
      });
      setReview(response.review);
      setAssets([]);
      setDraftDecisions({});
      setShowSubmitDialog(false);
      try {
        await props.onSubmit?.(assets, Object.fromEntries(decisions.map((item) => [item.assetId, item.action])));
      } catch {
        setError('审核结果已保存，但暂时无法通知伙伴，请稍后继续对话');
      }
    } catch {
      setShowSubmitDialog(false);
      setError('素材审核结果暂时无法保存，请稍后重试');
    } finally {
      setSubmitting(false);
    }
  };

  const approvedCount = review ? Object.values(review.decisions).filter((decision) => decision === 'approved').length : 0;
  const discardedCount = review ? Object.values(review.decisions).filter((decision) => decision !== 'approved').length : 0;

  if (loading) {
    return <section data-testid="game-asset-browser" className="surface-card flex min-h-28 w-full items-center justify-center rounded-2xl border border-border/70 bg-background text-foreground shadow-none"><Loader2 className="h-5 w-5 animate-spin" /></section>;
  }

  if (loadFailure === 'stale') {
    return (
      <section
        data-testid="game-asset-browser-stale"
        className="flex min-h-24 w-full items-center rounded-md border border-foreground/15 bg-background px-4 py-3 text-foreground shadow-soft"
      >
        <p className="text-pretty text-sm font-medium">旧素材卡片已失效，已自动跳过，不影响继续对话</p>
      </section>
    );
  }

  if (loadFailure === 'retryable') {
    return (
      <section
        data-testid="game-asset-browser-retryable"
        className="flex min-h-24 w-full items-center justify-between gap-3 rounded-md border border-foreground/15 bg-background px-4 py-3 text-foreground shadow-soft"
      >
        <p className="text-pretty text-sm font-medium">素材卡片暂时无法加载，不影响继续对话</p>
        <Button
          type="button"
          className="h-10 shrink-0 border border-foreground/15 bg-brand-soft font-semibold text-foreground transition-transform active:scale-[0.985]"
          onClick={() => void load()}
        >
          <RefreshCw className="mr-1 h-4 w-4" />重新加载
        </Button>
      </section>
    );
  }

  if (review?.status === 'resolved' && review.candidateIds.length > 0) {
    return (
      <section data-testid="game-asset-review-summary" className="surface-card w-full rounded-2xl border border-border/70 bg-background px-3 py-3 text-foreground shadow-none">
        <div className="flex items-start gap-2">
          <Check className="mt-0.5 h-4 w-4 shrink-0 text-emerald-700" />
          <div>
            <p className="text-sm font-semibold">本轮审核已完成</p>
            <p className="mt-1 text-xs font-medium leading-5 text-muted-foreground">纳入开发 {approvedCount} 个，舍弃 {discardedCount} 个。未处理素材不会自动带入下一轮。</p>
          </div>
        </div>
      </section>
    );
  }

  return (
    <section data-testid="game-asset-browser" className="surface-card w-full rounded-2xl border border-border/70 bg-background px-3 py-3 text-foreground shadow-none">
      <div className="flex items-start justify-between gap-3">
        <div>
          <h3 className="text-sm font-semibold">素材审核台</h3>
          <p className="text-xs font-medium text-muted-foreground">先逐项选择，全部选完后一次性提交审核结果。</p>
        </div>
        {review ? <span className="rounded border border-foreground/15 bg-white px-2 py-1 text-[10px] font-semibold">待处理 {review.pendingAssetIds.length} 个</span> : null}
      </div>

      {error ? <p className="mt-3 rounded border border-red-400 bg-red-50 p-2 text-xs font-medium text-red-700">{error}</p> : null}
      {!error && assets.length === 0 ? (
        <p className="mt-3 rounded border border-dashed border-foreground/15 bg-white p-3 text-xs font-medium">Agent 本次没有提交可审核的素材。未处理内容不会自动从旧批次带入。</p>
      ) : null}
      {assets.length > 0 ? (
        <div className="mt-3 flex gap-3 overflow-x-auto pb-2" data-testid="game-asset-candidate-list">
          {assets.map((asset) => {
            const selectedAction = draftDecisions[asset.id];
            return (
              <article key={asset.id} className={`w-56 shrink-0 overflow-hidden rounded-md border border-foreground/15 bg-white shadow-soft ${selectedAction ? 'ring-4 ring-accent/40' : ''}`}>
                <button type="button" className="flex h-28 w-full items-center justify-center overflow-hidden border-b border-foreground/15 bg-background" onClick={() => setPreviewAsset(asset)}>
                  {asset.previewDataUrl ? <img src={asset.previewDataUrl} alt={asset.name} className="h-full w-full object-contain" />
                    : asset.mediaKind === 'audio' ? <Headphones className="h-10 w-10 text-brand" />
                      : asset.mediaKind === 'bundle' ? <Archive className="h-10 w-10 text-accent" />
                        : <ImageIcon className="h-10 w-10 text-slate-400" />}
                </button>
                <div className="space-y-2 p-3">
                  <div className="flex items-start justify-between gap-2"><strong className="line-clamp-2 text-xs">{asset.name}</strong><Badge className="border border-foreground/15 bg-surface-subtle text-[9px] text-foreground">{selectedAction ? actionLabel(selectedAction) : asset.status}</Badge></div>
                  <p className="line-clamp-2 text-[11px] font-medium">{asset.purpose || '未填写用途'}</p>
                  <p className="truncate text-[10px] text-muted-foreground">来源：{asset.source || '未填写'}</p>
                  <p className="truncate text-[10px] text-muted-foreground">授权：{asset.license || '未填写'}</p>
                  {asset.audioDataUrl ? <audio controls preload="metadata" className="h-8 w-full" src={asset.audioDataUrl} /> : null}
                  <div className="grid grid-cols-2 gap-2">
                    <Button type="button" size="sm" disabled={submitting} className={`h-8 border border-foreground/15 text-[11px] font-semibold text-foreground ${selectedAction === 'approve' ? 'bg-brand-soft' : 'bg-white'}`} aria-pressed={selectedAction === 'approve'} aria-label={`纳入开发 ${asset.name}`} onClick={() => chooseAction(asset.id, 'approve')}>纳入开发</Button>
                    <Button type="button" size="sm" variant="outline" disabled={submitting} className={`h-8 border border-foreground/15 text-[11px] font-semibold ${selectedAction === 'discard' ? 'bg-accent-soft' : ''}`} aria-pressed={selectedAction === 'discard'} aria-label={`舍弃 ${asset.name}`} onClick={() => chooseAction(asset.id, 'discard')}>舍弃</Button>
                  </div>
                  <Button type="button" size="sm" variant="outline" disabled={submitting} className={`h-8 w-full border border-foreground/15 text-[11px] font-semibold ${selectedAction === 'replace' ? 'bg-surface-subtle' : ''}`} aria-pressed={selectedAction === 'replace'} aria-label={`重新寻找 ${asset.name}`} onClick={() => chooseAction(asset.id, 'replace')}><Search className="mr-1 h-3 w-3" />不合适，重新寻找</Button>
                </div>
              </article>
            );
          })}
        </div>
      ) : null}

      {assets.length > 0 ? (
        <div className="mt-2 flex items-center justify-between gap-3 border-t border-foreground/15 pt-3">
          <p className="text-[10px] font-medium text-muted-foreground">已选择 {selectedCount} / {assets.length} 个{allAssetsSelected ? '，可以提交' : `，还需选择 ${assets.length - selectedCount} 个`}</p>
          <Button type="button" size="sm" disabled={!allAssetsSelected || submitting} className="border border-foreground/15 bg-brand-soft text-[11px] font-semibold text-foreground" onClick={() => setShowSubmitDialog(true)}>查看并提交本轮结果</Button>
        </div>
      ) : null}

      {review && (approvedCount > 0 || discardedCount > 0) ? <p className="mt-2 text-[10px] font-medium text-muted-foreground">本轮已提交：纳入 {approvedCount} 个，舍弃 {discardedCount} 个。未处理素材不会自动带入下一轮。</p> : null}

      {showSubmitDialog ? (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-foreground/20 p-5" role="dialog" aria-modal="true" aria-label="确认提交本轮素材审核结果">
          <div className="max-h-[85vh] w-full max-w-2xl overflow-auto rounded-lg border border-foreground/15 bg-background p-5 shadow-soft">
            <div className="flex items-start justify-between gap-3"><div><h3 className="text-lg font-semibold">确认提交本轮审核</h3><p className="text-sm font-medium text-muted-foreground">将一次性保存全部决定，并只发送一条汇总对话。</p></div><Button type="button" size="icon" variant="outline" aria-label="关闭提交确认" className="border border-foreground/15" onClick={() => setShowSubmitDialog(false)}><X className="h-4 w-4" /></Button></div>
            <div className="mt-4 grid gap-2 sm:grid-cols-3">
              {(['approve', 'discard', 'replace'] as const).map((action) => {
                const selected = assets.filter((asset) => draftDecisions[asset.id] === action);
                return <div key={action} className="rounded border border-foreground/15 bg-white p-3 text-xs"><p className="font-semibold">{actionLabel(action)}：{selected.length} 个</p><p className="mt-1 line-clamp-3 text-muted-foreground">{selected.map((asset) => asset.name).join('、') || '无'}</p></div>;
              })}
            </div>
            <div className="mt-5 flex justify-end gap-2"><Button type="button" variant="outline" disabled={submitting} className="border border-foreground/15 font-semibold" onClick={() => setShowSubmitDialog(false)}>返回修改</Button><Button type="button" disabled={submitting} className="border border-foreground/15 bg-brand-soft font-semibold text-foreground" onClick={() => void submitBatch()}>{submitting ? <Loader2 className="mr-1 h-4 w-4 animate-spin" /> : null}确认并一次性提交</Button></div>
          </div>
        </div>
      ) : null}

      {previewAsset ? (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-foreground/20 p-5" role="dialog" aria-modal="true" aria-label={`${previewAsset.name} 素材预览`}>
          <div className="max-h-[85vh] w-full max-w-3xl overflow-auto rounded-lg border border-foreground/15 bg-background p-5 shadow-soft">
            <div className="flex items-start justify-between gap-3"><div><h3 className="text-lg font-semibold">{previewAsset.name}</h3><p className="text-sm font-medium text-muted-foreground">{previewAsset.purpose}</p></div><Button type="button" size="icon" variant="outline" aria-label="关闭素材预览" className="border border-foreground/15" onClick={() => setPreviewAsset(null)}><X className="h-4 w-4" /></Button></div>
            {previewAsset.previewDataUrl ? <img src={previewAsset.previewDataUrl} alt={previewAsset.name} className="mt-4 max-h-[50vh] w-full rounded border border-foreground/15 bg-white object-contain" /> : null}
            {previewAsset.audioDataUrl ? <audio controls autoPlay className="mt-4 w-full" src={previewAsset.audioDataUrl} /> : null}
            {previewAsset.manifest.length > 0 ? <div className="mt-4"><h4 className="text-sm font-semibold">文件清单</h4><ul className="mt-2 max-h-52 overflow-auto rounded border border-foreground/15 bg-white p-3 text-xs">{previewAsset.manifest.map((item) => <li key={item} className="py-0.5">{item}</li>)}</ul></div> : null}
            {previewAsset.unavailableReason ? <p className="mt-4 rounded border border-amber-400 bg-amber-50 p-3 text-xs font-medium">{previewAsset.unavailableReason}</p> : null}
          </div>
        </div>
      ) : null}
    </section>
  );
}
