'use client';

import { useState, useCallback, useRef, useMemo, useEffect } from 'react';
import { Button } from '@/components/ui/button';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Label } from '@/components/ui/label';
import { useAuth } from '@/lib/auth-store';
import { useCustomApiKeys } from '@/lib/custom-api-store';
import { useManagedSystemApis } from '@/lib/managed-model-store';
import {
  VIDEO_ASPECT_RATIOS,
  VIDEO_DURATIONS_SHORT,
  IMG2VIDEO_CAMERA_MOVEMENTS,
  isCustomModel,
  isSystemModel,
  getCustomKeyId,
  getSystemApiId,
  buildCustomModelId,
  buildSystemModelId,
  calcVideoCredits,
} from '@/lib/model-config';
import { Sparkles, Loader2, Download, Upload, Wand2, Film, History, ChevronDown, ChevronUp, Plus, X, KeyRound, Share2 } from 'lucide-react';
import { useCreationHistory, getCreationMode, isPlaceholder, shareToGallery, isUrlPublished, type CreationRecord } from '@/lib/creation-history-store';
import { addCreditRecord } from '@/lib/credit-records-store';
import { downloadFile } from '@/lib/utils';
import { runGenerationFinalCountdown, runGenerationJob, type GenerationJobStatus } from '@/lib/generation-job-client';
import { useSiteConfig } from '@/lib/site-config';
import { toast } from 'sonner';
import Link from 'next/link';
import { CreationDetailDialog } from '@/components/creation-detail-dialog';
import { GenerationErrorPanel, createGenerationError, type GenerationErrorState } from '@/components/create/generation-error-panel';
import { ExpandablePromptTextarea } from '@/components/create/expandable-prompt-textarea';
import { GenerationLoadingPanel } from '@/components/create/generation-loading-panel';
import { compressImageFileForUpload } from '@/lib/browser-image-compression';

interface RefImage {
  id: string;
  dataUrl: string;
  name: string;
}

export function ImageToVideoPanel() {
  const { user, accessToken } = useAuth();
  const { config: siteConfig } = useSiteConfig();
  const membershipEnabled = siteConfig.membershipEnabled !== false;
  const { videoKeys, textKeys } = useCustomApiKeys();
  const managedSystemApis = useManagedSystemApis();

  const [prompt, setPrompt] = useState('');
  const [negativePrompt, setNegativePrompt] = useState('');
  const [aspectRatio, setAspectRatio] = useState('16:9');
  const [duration, setDuration] = useState('4');
  const [cameraMovement, setCameraMovement] = useState(IMG2VIDEO_CAMERA_MOVEMENTS[0]);
  const [refImages, setRefImages] = useState<RefImage[]>([]);

  const [generating, setGenerating] = useState(false);
  const [generationStartedAt, setGenerationStartedAt] = useState(() => Date.now());
  const [generationJobStatus, setGenerationJobStatus] = useState<GenerationJobStatus | null>(null);
  const [finalCountdownSeconds, setFinalCountdownSeconds] = useState<number | null>(null);
  const [results, setResults] = useState<string[]>([]);
  const [generationError, setGenerationError] = useState<GenerationErrorState | null>(null);
  const [optimizing, setOptimizing] = useState(false);

  const { records, add: addRecord } = useCreationHistory();
  const [showHistory, setShowHistory] = useState(false);

  // History detail dialog
  const [selectedHistoryRecord, setSelectedHistoryRecord] = useState<CreationRecord | null>(null);
  const videoHistory = records.filter(r => getCreationMode(r) === 'img2video');
  const fileInputRef = useRef<HTMLInputElement>(null);

  const systemVideoApis = managedSystemApis.filter(api => api.type === 'video' && api.isActive);
  const systemTextApis = managedSystemApis.filter(api => api.type === 'text' && api.isActive);

  // Model options — only system + custom (no builtin)
  const modelOptions = useMemo(() => [
    ...systemVideoApis.map(api => ({ id: buildSystemModelId(api.id), label: `${api.name} (系统)`, group: '系统模型' })),
    ...videoKeys.map(k => ({ id: buildCustomModelId(k.id), label: `${k.modelName || k.provider} (自定义)`, group: '自定义模型' })),
  ], [systemVideoApis, videoKeys]);

  const hasModels = modelOptions.length > 0;

  const [selectedModel, setSelectedModel] = useState('');
  useEffect(() => {
    if (modelOptions.length > 0 && !modelOptions.find(o => o.id === selectedModel)) {
      const customOpt = modelOptions.find(o => o.group === '自定义模型');
      setSelectedModel(customOpt ? customOpt.id : modelOptions[0].id);
    }
  }, [modelOptions, selectedModel]);

  const textModelOptions = useMemo(() => [
    ...textKeys.map(k => ({ id: buildCustomModelId(k.id), label: `${k.modelName || k.provider} (自定义)`, config: { customApiKeyId: k.id, modelName: k.modelName } })),
    ...systemTextApis.map(api => ({ id: buildSystemModelId(api.id), label: `${api.name} (系统)`, config: { systemApiId: api.id, modelName: api.modelName } })),
  ], [textKeys, systemTextApis]);

  const getCurrentModelLabel = useCallback(() => {
    if (isCustomModel(selectedModel)) {
      const key = videoKeys.find(k => k.id === getCustomKeyId(selectedModel));
      return key?.modelName || key?.provider || '自定义模型';
    }
    if (isSystemModel(selectedModel)) {
      const api = systemVideoApis.find(a => a.id === getSystemApiId(selectedModel));
      return api?.name || '系统模型';
    }
    return 'AI模型';
  }, [selectedModel, videoKeys, systemVideoApis]);

  const handleOptimizePrompt = useCallback(async () => {
    if (!prompt.trim()) { toast.error('请先输入视频描述'); return; }
    if (!user || !accessToken) { toast.error('请先登录后再优化提示词'); return; }
    if (textModelOptions.length === 0) { toast.error('未配置文本模型'); return; }

    setOptimizing(true);
    try {
      const textModel = textModelOptions[0];
      const modelLabel = getCurrentModelLabel();
      const res = await fetch('/api/generate/suggest-prompt', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
        },
        body: JSON.stringify({
          prompt: prompt.trim(),
          modelName: textModel.config.modelName,
          customApiConfig: textModel.config,
          systemPrefix: `针对${modelLabel}视频生成优化提示词`,
        }),
      });
      const data = await res.json().catch(() => ({}));
      if (res.ok) {
        if (data.prompt) {
          setPrompt(data.prompt);
          if (typeof data.negativePrompt === 'string' && data.negativePrompt.trim()) {
            setNegativePrompt(data.negativePrompt.trim());
          }
          toast.success('提示词已优化');
        }
        else toast.error(data.error || '优化失败');
      } else toast.error(data.error || '提示词优化请求失败');
    } catch (err: unknown) {
      if (err instanceof DOMException && err.name === 'AbortError') {
        toast.error('请求超时，视频生成可能需要更长时间');
      } else {
        toast.error(err instanceof Error ? err.message : '网络错误，请重试');
      }
    }
    finally { setOptimizing(false); }
  }, [prompt, user, accessToken, textModelOptions, getCurrentModelLabel]);

  const addRefImageFiles = useCallback((files: File[]) => {
    const imageFiles = files.filter(file => file.type.startsWith('image/'));
    if (imageFiles.length === 0) {
      toast.error('请上传图片文件');
      return;
    }
    void (async () => {
      const refs: RefImage[] = [];
      let compressedCount = 0;

      for (const file of imageFiles) {
        try {
          const result = await compressImageFileForUpload(file);
          if (result.compressed) compressedCount += 1;
          refs.push({
            id: `ref-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`,
            dataUrl: result.dataUrl,
            name: result.name,
          });
        } catch (err) {
          toast.error(err instanceof Error ? err.message : '图片读取失败');
        }
      }

      if (refs.length > 0) {
        setRefImages(prev => [...prev, ...refs]);
      }
      if (compressedCount > 0) {
        toast.info(`已自动压缩 ${compressedCount} 张参考图`);
      }
    })();
  }, []);

  const addRefImageUrl = useCallback((value: string) => {
    const url = value.trim();
    if (!/^https?:\/\/\S+/i.test(url)) {
      toast.error('请粘贴有效的图片 URL');
      return false;
    }
    setRefImages(prev => [...prev, { id: `ref-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`, dataUrl: url, name: '图片 URL' }]);
    toast.success('已添加图片 URL');
    return true;
  }, []);

  const handleFileChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
    const files = e.target.files;
    if (!files || files.length === 0) return;
    addRefImageFiles(Array.from(files));
    e.target.value = '';
  }, [addRefImageFiles]);

  const handleUploadDrop = useCallback((event: React.DragEvent<HTMLDivElement>) => {
    event.preventDefault();
    const files = Array.from(event.dataTransfer.files);
    if (files.length > 0) {
      addRefImageFiles(files);
      return;
    }
    const url = event.dataTransfer.getData('text/uri-list') || event.dataTransfer.getData('text/plain');
    if (url) addRefImageUrl(url);
  }, [addRefImageFiles, addRefImageUrl]);

  const handleUploadPaste = useCallback((event: React.ClipboardEvent<HTMLDivElement>) => {
    const files = Array.from(event.clipboardData.files);
    if (files.length > 0) {
      event.preventDefault();
      addRefImageFiles(files);
      return;
    }
    const text = event.clipboardData.getData('text/plain');
    if (/^https?:\/\/\S+/i.test(text.trim())) {
      event.preventDefault();
      addRefImageUrl(text);
    }
  }, [addRefImageFiles, addRefImageUrl]);

  const removeRefImage = useCallback((id: string) => {
    setRefImages(prev => prev.filter(img => img.id !== id));
  }, []);

  const credits = calcVideoCredits(duration, selectedModel);

  const handleGenerate = useCallback(async () => {
    if (!user) { toast.error('请先登录'); return; }
    if (refImages.length === 0 && !prompt.trim()) { toast.error('请上传参考图片或输入视频描述'); return; }

    setGenerationError(null);
    setResults([]);
    setGenerationStartedAt(Date.now());
    setGenerationJobStatus(null);
    setFinalCountdownSeconds(null);
    setGenerating(true);
    try {
      const primaryImage = refImages[0]?.dataUrl;
      let requestBody: Record<string, unknown> = {
        prompt: prompt.trim() || undefined,
        negativePrompt: negativePrompt.trim() || undefined,
        model: selectedModel,
        aspectRatio,
        duration: Number(duration),
        fps: 30,
        image: primaryImage,
        extraImages: refImages.length > 1 ? refImages.slice(1).map(img => img.dataUrl) : undefined,
        images: refImages.length > 0 ? refImages.map(img => img.dataUrl) : undefined,
      };

      if (isCustomModel(selectedModel)) {
        const key = videoKeys.find(k => k.id === getCustomKeyId(selectedModel));
        if (key) {
          requestBody = { ...requestBody, model: key.modelName, customApiConfig: { customApiKeyId: key.id, modelName: key.modelName } };
        }
      } else if (isSystemModel(selectedModel)) {
        const api = systemVideoApis.find(a => a.id === getSystemApiId(selectedModel));
        if (api) {
          requestBody = { ...requestBody, model: api.modelName, customApiConfig: { systemApiId: api.id, modelName: api.modelName } };
        }
      }
      const data = await runGenerationJob<{ videos?: string[]; error?: string }>(
        'video',
        requestBody,
        { timeoutMs: 600_000, onStatus: setGenerationJobStatus },
      );
      await runGenerationFinalCountdown(setFinalCountdownSeconds, 3);
      if (data.videos && data.videos.length > 0) {
        setResults(data.videos);
        setGenerationError(null);
        for (const url of data.videos) {
          addRecord({
            type: 'video', url, prompt: prompt.trim(),
            negativePrompt: negativePrompt.trim() || undefined,
            model: selectedModel,
            modelLabel: getCurrentModelLabel(),
            isCustomModel: isCustomModel(selectedModel) || isSystemModel(selectedModel),
            referenceImage: primaryImage,
            referenceImages: refImages.map(img => img.dataUrl),
            params: { creationMode: 'img2video', aspectRatio, duration, cameraMovement, refImageCount: refImages.length },
          });
        }
        toast.success('视频生成成功');
        if (membershipEnabled && credits > 0 && user) {
          const currentCredits = typeof user.creditsBalance === 'number' ? user.creditsBalance : 0;
          addCreditRecord({
            type: 'consume',
            amount: -credits,
            balanceAfter: Math.max(0, currentCredits - credits),
            description: `图生视频 - ${getCurrentModelLabel()}`,
          });
        }
      } else {
        setGenerationError(createGenerationError(data.error || '视频生成失败'));
      }
    } catch (err: unknown) {
      if (err instanceof DOMException && err.name === 'AbortError') {
        setGenerationError(createGenerationError('请求超时，视频生成可能需要更长时间'));
      } else {
        setGenerationError(createGenerationError(err instanceof Error ? err.message : '网络错误，请重试'));
      }
    }
    finally { setGenerating(false); setFinalCountdownSeconds(null); }
  }, [prompt, negativePrompt, selectedModel, aspectRatio, duration, cameraMovement, refImages, user, videoKeys, systemVideoApis, getCurrentModelLabel, addRecord, credits, membershipEnabled]);

  const handleDownload = useCallback(async (url: string, index: number) => {
    const result = await downloadFile(url, `miaojing-img2vid-${Date.now()}-${index}.mp4`);
    if (!result.ok) toast.error(result.error || '下载失败');
  }, []);

  const handleShareToGallery = useCallback((url: string) => {
    if (isUrlPublished(url)) {
      toast.info('该作品已分享到画廊');
      return;
    }
    shareToGallery({
      type: 'video',
      url,
      prompt: prompt.trim(),
      model: selectedModel,
      modelLabel: getCurrentModelLabel(),
    });
    toast.success('已分享到画廊');
  }, [prompt, selectedModel, getCurrentModelLabel]);

  return (
    <div className="grid min-h-[600px] grid-cols-1 gap-6 xl:grid-cols-[minmax(0,4fr)_minmax(0,6fr)]">
      {/* Left: Settings */}
      <div className="min-w-0 space-y-5 overflow-y-auto max-h-[calc(100vh-200px)] pr-2">
        {/* Reference Image */}
        <div className="space-y-2">
          <Label>参考图片 <span className="text-destructive">*</span> <span className="text-muted-foreground text-xs">可上传多张</span></Label>
          <input type="file" ref={fileInputRef} className="hidden" accept="image/*" multiple onChange={handleFileChange} />
          <div
            tabIndex={0}
            className="flex min-h-[224px] items-center justify-center rounded-2xl border border-dashed border-border/80 bg-background/50 p-5 transition-colors hover:border-primary/60 focus:outline-none focus:ring-2 focus:ring-primary/40"
            onDragOver={(event) => event.preventDefault()}
            onDrop={handleUploadDrop}
            onPaste={handleUploadPaste}
          >
            {refImages.length > 0 ? (
              <div className="grid w-full grid-cols-3 gap-3">
                {refImages.map(img => (
                  <div key={img.id} className="liquid-glass-soft relative aspect-square overflow-hidden rounded-2xl">
                    {/* eslint-disable-next-line @next/next/no-img-element */}
                    <img src={img.dataUrl} alt={img.name} className="h-full w-full object-cover" />
                    <button
                      className="absolute right-1 top-1 flex h-5 w-5 items-center justify-center rounded-full bg-black/60 text-white"
                      onClick={() => removeRefImage(img.id)}
                    >
                      <X className="h-3 w-3" />
                    </button>
                  </div>
                ))}
                <button
                  className="flex aspect-square flex-col items-center justify-center gap-2 rounded-2xl border border-dashed border-border text-muted-foreground transition-colors hover:border-primary/60 hover:text-primary"
                  type="button"
                  onClick={() => fileInputRef.current?.click()}
                >
                  <Plus className="h-5 w-5" />
                  <span className="text-xs">添加</span>
                </button>
              </div>
            ) : (
              <button
                className="flex min-h-[189px] w-full flex-col items-center justify-center gap-2 text-center text-muted-foreground"
                type="button"
                onClick={() => fileInputRef.current?.click()}
              >
                <Upload className="h-14 w-14 opacity-30" />
                <span className="text-base font-semibold text-foreground">上传参考图片</span>
                <span className="text-sm">点击上传、拖入图片、Ctrl+V 粘贴图片或图片 URL</span>
              </button>
            )}
          </div>
        </div>

        {/* Model Selection */}
        <div className="space-y-2">
          <Label>视频模型</Label>
          {hasModels ? (
            <Select value={selectedModel} onValueChange={setSelectedModel}>
              <SelectTrigger><SelectValue placeholder="选择模型" /></SelectTrigger>
              <SelectContent>
                {modelOptions.map(opt => (
                  <SelectItem key={opt.id} value={opt.id}>{opt.label}</SelectItem>
                ))}
              </SelectContent>
            </Select>
          ) : (
            <div className="liquid-glass-soft rounded-2xl border-dashed p-4 text-center space-y-2">
              <KeyRound className="h-8 w-8 mx-auto text-muted-foreground/50" />
              <p className="text-sm text-muted-foreground">暂无可用模型</p>
              <Link href="/profile" className="text-sm text-primary hover:underline">
                前往 我的 → API 中添加API密钥
              </Link>
            </div>
          )}
        </div>

        <div className="space-y-2">
          <div className="flex items-center justify-between">
            <Label>视频描述 <span className="text-muted-foreground text-xs">(可选)</span></Label>
            {textModelOptions.length > 0 && (
              <Button variant="ghost" size="sm" className="h-7 gap-1.5 text-xs text-primary hover:text-primary" onClick={handleOptimizePrompt} disabled={optimizing || !prompt.trim()}>
                {optimizing ? <Loader2 className="h-3 w-3 animate-spin" /> : <Wand2 className="h-3 w-3" />}
                {optimizing ? '优化中...' : '优化提示词'}
              </Button>
            )}
          </div>
          <ExpandablePromptTextarea
            title="视频描述"
            placeholder="描述你想要的视频效果..."
            rows={3}
            className="h-32 resize-none overflow-y-auto"
            value={prompt}
            onValueChange={setPrompt}
          />
        </div>

        <div className="space-y-2">
          <Label>负面提示词 <span className="text-muted-foreground text-xs">(可选)</span></Label>
          <ExpandablePromptTextarea
            title="负面提示词"
            placeholder="不希望出现的元素..."
            rows={2}
            className="h-24 resize-none overflow-y-auto"
            value={negativePrompt}
            onValueChange={setNegativePrompt}
          />
        </div>

        <div className="grid grid-cols-2 gap-3">
          <div className="space-y-2">
            <Label>画面比例</Label>
            <Select value={aspectRatio} onValueChange={setAspectRatio}>
              <SelectTrigger><SelectValue /></SelectTrigger>
              <SelectContent>
                {VIDEO_ASPECT_RATIOS.map(ar => (
                  <SelectItem key={ar.value} value={ar.value}>{ar.label}</SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
          <div className="space-y-2">
            <Label>视频时长</Label>
            <Select value={duration} onValueChange={setDuration}>
              <SelectTrigger><SelectValue /></SelectTrigger>
              <SelectContent>
                {VIDEO_DURATIONS_SHORT.map(d => (
                  <SelectItem key={d.value} value={d.value}>{d.label}{membershipEnabled && ` (${d.credits} 积分)`}</SelectItem>
                ))}
              </SelectContent>
            </Select>
          </div>
        </div>

        <div className="space-y-2">
          <Label>镜头运动</Label>
          <Select value={cameraMovement} onValueChange={setCameraMovement}>
            <SelectTrigger><SelectValue /></SelectTrigger>
            <SelectContent>
              {IMG2VIDEO_CAMERA_MOVEMENTS.map(c => (
                <SelectItem key={c} value={c}>{c}</SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>

        <Button className="w-full gap-2" size="lg" onClick={handleGenerate} disabled={generating || !hasModels}>
          {generating ? (<><Loader2 className="h-4 w-4 animate-spin" />生成中...</>) : (<><Sparkles className="h-4 w-4" />生成视频 {membershipEnabled && credits > 0 && `(${credits} 积分)`}</>)}
        </Button>
      </div>

      {/* Right: Results + History */}
      <div className="min-w-0 space-y-4">
        {generating ? (
          <div className="liquid-glass min-h-[300px] overflow-hidden rounded-2xl border-dashed text-muted-foreground">
            <GenerationLoadingPanel
              startedAt={generationStartedAt}
              estimateSeconds={300}
              jobStatus={generationJobStatus}
              finalCountdownSeconds={finalCountdownSeconds}
              title="正在生成视频"
            />
          </div>
        ) : generationError ? (
          <GenerationErrorPanel error={generationError} />
        ) : results.length > 0 ? (
          <div className="space-y-3">
            <div className="flex items-center gap-2 text-sm font-medium"><Film className="h-4 w-4" />生成结果</div>
            {results.map((url, i) => (
              <div key={i} className="liquid-glass-soft overflow-hidden rounded-2xl">
                <video src={url} controls className="w-full" />
                <div className="p-2 flex justify-end gap-2">
                  <Button size="sm" variant="outline" className="gap-1" onClick={() => handleShareToGallery(url)}><Share2 className="h-3.5 w-3.5" />分享</Button>
                  <Button size="sm" variant="outline" className="gap-1" onClick={() => handleDownload(url, i)}><Download className="h-3.5 w-3.5" />下载</Button>
                </div>
              </div>
            ))}
          </div>
        ) : (
          <div className="liquid-glass flex min-h-[300px] flex-col items-center justify-center rounded-2xl border-dashed py-24 text-muted-foreground">
            <Film className="h-14 w-14 mb-3 opacity-20" />
            <p className="text-sm">生成结果将显示在这里</p>
          </div>
        )}

        {videoHistory.length > 0 && (
          <div className="space-y-2">
            <button className="flex items-center gap-2 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors" onClick={() => setShowHistory(!showHistory)}>
              <History className="h-4 w-4" />历史创作 ({videoHistory.length})
              {showHistory ? <ChevronUp className="h-3.5 w-3.5" /> : <ChevronDown className="h-3.5 w-3.5" />}
            </button>
            {showHistory && (
              <div className="grid grid-cols-2 gap-2 max-h-[400px] overflow-y-auto">
                {videoHistory.map(record => (
                  <div
                    key={record.id}
                    className="liquid-glass-soft group relative cursor-pointer overflow-hidden rounded-xl"
                    onClick={() => setSelectedHistoryRecord(record)}
                  >
                    {isPlaceholder(record.url) ? (
                      <div className="w-full aspect-video flex items-center justify-center"><Film className="h-6 w-6 text-muted-foreground/30" /></div>
                    ) : (
                      <div className="w-full aspect-video relative overflow-hidden">
                        <video src={record.url} className="w-full h-full object-cover" preload="metadata" />
                        <div className="absolute inset-0 flex items-center justify-center bg-black/30 opacity-0 group-hover:opacity-100 transition-opacity">
                          <div className="h-8 w-8 rounded-full bg-white/90 flex items-center justify-center">
                            <Film className="h-4 w-4 text-black ml-0.5" />
                          </div>
                        </div>
                      </div>
                    )}
                    <div className="p-1.5"><p className="text-xs text-muted-foreground line-clamp-1">{record.prompt}</p></div>
                  </div>
                ))}
              </div>
            )}
          </div>
        )}
      </div>

      {/* History Detail Dialog */}
      <CreationDetailDialog
        record={selectedHistoryRecord}
        open={!!selectedHistoryRecord}
        onClose={() => setSelectedHistoryRecord(null)}
      />
    </div>
  );
}
