import { useState, useEffect, useRef, useCallback } from 'react';
import { useAssetLibraryStore } from '../store/assetLibrary';
import { assetsApi, tosThumb } from '../lib/api';
import { showToast } from './Toast';
import { ImageLightbox } from './ImageLightbox';
import type { AssetGroup, AssetItem } from '../types';
import styles from './AssetLibraryModal.module.css';

/** Validate asset file before upload. Returns error message or null if valid. */
async function validateAssetFile(file: File): Promise<string | null> {
  const ct = file.type || '';

  if (ct.startsWith('image/')) {
    // Format: accept all image/* since backend checks ext
    if (file.size > 30 * 1024 * 1024) return '图片文件不能超过 30MB';
    // Dimension check
    try {
      const dims = await new Promise<{ w: number; h: number }>((resolve, reject) => {
        const img = new Image();
        const url = URL.createObjectURL(file);
        img.onload = () => { resolve({ w: img.naturalWidth, h: img.naturalHeight }); URL.revokeObjectURL(url); };
        img.onerror = () => { reject(); URL.revokeObjectURL(url); };
        img.src = url;
      });
      if (dims.w <= 300 || dims.h <= 300) return `图片尺寸过小（${dims.w}×${dims.h}），宽高需在 300~6000 像素之间`;
      if (dims.w >= 6000 || dims.h >= 6000) return `图片尺寸过大（${dims.w}×${dims.h}），宽高需在 300~6000 像素之间`;
      const ratio = dims.w / dims.h;
      if (ratio <= 0.4 || ratio >= 2.5) return `图片比例不支持（${dims.w}×${dims.h}），宽高比需在 0.4~2.5 之间`;
    } catch {
      // Can't read dimensions (e.g. HEIC), skip — backend will validate
    }
    return null;
  }

  if (ct.startsWith('video/')) {
    if (ct !== 'video/mp4' && ct !== 'video/quicktime') return '仅支持 MP4 和 MOV 格式的视频';
    if (file.size > 50 * 1024 * 1024) return '视频文件不能超过 50MB';
    // Duration + dimension check
    try {
      const info = await new Promise<{ dur: number; w: number; h: number }>((resolve, reject) => {
        const vid = document.createElement('video');
        const url = URL.createObjectURL(file);
        const timeout = setTimeout(() => { reject(); URL.revokeObjectURL(url); }, 10000);
        vid.addEventListener('loadedmetadata', () => {
          clearTimeout(timeout);
          resolve({ dur: vid.duration, w: vid.videoWidth, h: vid.videoHeight });
          URL.revokeObjectURL(url);
        });
        vid.addEventListener('error', () => { clearTimeout(timeout); reject(); URL.revokeObjectURL(url); });
        vid.src = url;
      });
      if (info.dur < 2 || info.dur > 15.4) return `视频时长需在 2~15 秒之间（当前 ${info.dur.toFixed(1)} 秒）`;
      if (info.w < 300 || info.h < 300) return `视频尺寸过小（${info.w}×${info.h}），宽高需在 300~6000 像素之间`;
      if (info.w > 6000 || info.h > 6000) return `视频尺寸过大（${info.w}×${info.h}），宽高需在 300~6000 像素之间`;
      const ratio = info.w / info.h;
      if (ratio < 0.4 || ratio > 2.5) return `视频比例不支持（${info.w}×${info.h}），宽高比需在 0.4~2.5 之间`;
      const pixels = info.w * info.h;
      if (pixels < 409600) return `视频像素过低（${info.w}×${info.h}=${pixels.toLocaleString()}），需在 409,600~927,408 之间`;
      if (pixels > 927408) return `视频像素过高（${info.w}×${info.h}=${pixels.toLocaleString()}），需在 409,600~927,408 之间`;
    } catch {
      // Can't read metadata, skip — backend will validate
    }
    return null;
  }

  if (ct.startsWith('audio/')) {
    if (ct !== 'audio/mpeg' && ct !== 'audio/wav') return '仅支持 MP3 和 WAV 格式的音频';
    if (file.size > 15 * 1024 * 1024) return '音频文件不能超过 15MB';
    // Duration check
    try {
      const dur = await new Promise<number>((resolve, reject) => {
        const audio = new Audio();
        const url = URL.createObjectURL(file);
        const timeout = setTimeout(() => { reject(); URL.revokeObjectURL(url); }, 10000);
        audio.addEventListener('loadedmetadata', () => {
          clearTimeout(timeout);
          resolve(audio.duration);
          URL.revokeObjectURL(url);
        });
        audio.addEventListener('error', () => { clearTimeout(timeout); reject(); URL.revokeObjectURL(url); });
        audio.src = url;
      });
      if (dur < 2 || dur > 15.4) return `音频时长需在 2~15 秒之间（当前 ${dur.toFixed(1)} 秒）`;
    } catch {
      // Can't read metadata, skip
    }
    return null;
  }

  return '不支持的文件类型';
}

interface Props {
  open: boolean;
  onClose: () => void;
}

export function AssetLibraryModal({ open, onClose }: Props) {
  const [view, setView] = useState<'list' | 'detail' | 'upload'>('list');
  const [selectedGroup, setSelectedGroup] = useState<AssetGroup | null>(null);
  const [groupAssets, setGroupAssets] = useState<AssetItem[]>([]);
  const [newName, setNewName] = useState('');
  const [uploading, setUploading] = useState(false);
  const [editingName, setEditingName] = useState<{ id: number; value: string } | null>(null);
  const [uploadFile, setUploadFile] = useState<File | null>(null);
  const [uploadPreview, setUploadPreview] = useState<string | null>(null);
  const [dragOver, setDragOver] = useState(false);
  const [lightboxSrc, setLightboxSrc] = useState<string | null>(null);
  const fileInputRef = useRef<HTMLInputElement>(null);

  const groups = useAssetLibraryStore((s) => s.groups);
  const loading = useAssetLibraryStore((s) => s.loading);
  const total = useAssetLibraryStore((s) => s.total);
  const page = useAssetLibraryStore((s) => s.page);
  const loadGroups = useAssetLibraryStore((s) => s.loadGroups);
  const createGroup = useAssetLibraryStore((s) => s.createGroup);
  const pollAssetStatus = useAssetLibraryStore((s) => s.pollAssetStatus);

  const totalPages = Math.ceil(total / 20);

  useEffect(() => {
    if (open) {
      loadGroups(1);
      setView('list');
      setSelectedGroup(null);
    }
  }, [open, loadGroups]);

  const handleGroupClick = useCallback(async (group: AssetGroup) => {
    setSelectedGroup(group);
    try {
      const { data } = await assetsApi.getGroupDetail(group.id);
      const assets: AssetItem[] = data.assets || [];
      setGroupAssets(assets);
      // 对所有素材检查一次云端状态（处理中的更新状态，被删的清理掉）
      let needRefresh = false;
      const checks = assets.map((asset) =>
        assetsApi.pollStatus(asset.id).then(({ data: statusData }) => {
          if (statusData.status !== asset.status || statusData.status as string === 'deleted') {
            needRefresh = true;
          }
        }).catch(() => {})
      );
      Promise.all(checks).then(() => {
        if (needRefresh) {
          assetsApi.getGroupDetail(group.id).then(({ data: refreshed }) => {
            setGroupAssets(refreshed.assets || []);
          }).catch(() => {});
        }
      });
    } catch {
      setGroupAssets([]);
    }
    setView('detail');
  }, []);

  const handleBackToList = useCallback(() => {
    setView('list');
    setSelectedGroup(null);
    setGroupAssets([]);
    setEditingName(null);
    loadGroups(page);
  }, [loadGroups, page]);

  const handleRenameGroup = useCallback(async (id: number, name: string) => {
    try {
      await assetsApi.updateGroup(id, { name });
      showToast('重命名成功');
      setEditingName(null);
      loadGroups(page);
      if (selectedGroup && selectedGroup.id === id) {
        setSelectedGroup({ ...selectedGroup, name });
      }
    } catch {
      showToast('重命名失败');
    }
  }, [loadGroups, page, selectedGroup]);

  const handleUploadSubmit = useCallback(async () => {
    const trimmed = newName.trim();
    if (!trimmed || !uploadFile) return;
    if (trimmed.length > 64) { showToast('角色名称不能超过64个字符'); return; }
    if (trimmed.includes('&&')) { showToast('角色名称不能包含 &&'); return; }
    setUploading(true);
    const result = await createGroup(newName.trim(), uploadFile);
    setUploading(false);
    if (result) {
      pollAssetStatus(result.id);
      setNewName('');
      setUploadFile(null);
      if (uploadPreview) URL.revokeObjectURL(uploadPreview);
      setUploadPreview(null);
      handleBackToList();
    }
  }, [newName, uploadFile, createGroup, pollAssetStatus, uploadPreview, handleBackToList]);

  const handleFileSelect = useCallback(async (file: File) => {
    const error = await validateAssetFile(file);
    if (error) { showToast(error); return; }
    if (uploadPreview) URL.revokeObjectURL(uploadPreview);
    setUploadFile(file);
    setUploadPreview(file.type.startsWith('image/') ? URL.createObjectURL(file) : null);
  }, [uploadPreview]);

  const refreshGroupDetail = useCallback(async () => {
    if (!selectedGroup) return;
    try {
      const { data } = await assetsApi.getGroupDetail(selectedGroup.id);
      setGroupAssets(data.assets || []);
    } catch { /* ignore */ }
  }, [selectedGroup]);

  const handleAddAsset = useCallback(async (file: File) => {
    if (!selectedGroup) return;
    const error = await validateAssetFile(file);
    if (error) { showToast(error); return; }
    const formData = new FormData();
    formData.append('file', file);
    try {
      const { data } = await assetsApi.addAsset(selectedGroup.id, formData);
      setGroupAssets((prev) => [...prev, data]);
      // 轮询状态，完成后刷新详情
      const pollId = data.id;
      const pollInterval = setInterval(async () => {
        try {
          const { data: statusData } = await assetsApi.pollStatus(pollId);
          if (statusData.status !== 'processing') {
            clearInterval(pollInterval);
            if (statusData.status === 'active') showToast('素材已就绪');
            else if (statusData.status === 'deleted') showToast('素材在云端已被删除');
            else showToast('素材处理失败');
            refreshGroupDetail();
          }
        } catch {
          clearInterval(pollInterval);
        }
      }, 3000);
      showToast('图片已上传，处理中...');
    } catch {
      showToast('上传失败，请重试');
    }
  }, [selectedGroup, refreshGroupDetail]);

  const handleDrop = useCallback((e: React.DragEvent) => {
    e.preventDefault();
    setDragOver(false);
    const file = e.dataTransfer.files[0];
    if (file && (file.type.startsWith('image/') || file.type.startsWith('video/') || file.type.startsWith('audio/'))) {
      handleFileSelect(file);
    }
  }, [handleFileSelect]);

  if (!open) return null;

  return (
    <div className={styles.overlay} onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className={styles.modal}>
        {/* Header */}
        <div className={styles.header}>
          <div className={styles.headerLeft}>
            {view !== 'list' && (
              <button className={styles.backBtn} onClick={handleBackToList}>
                <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
                  <polyline points="15 18 9 12 15 6" />
                </svg>
              </button>
            )}
            <span className={styles.title}>
              {view === 'list' && '素材库'}
              {view === 'detail' && (selectedGroup?.name || '角色详情')}
              {view === 'upload' && '上传新角色'}
            </span>
          </div>
          <button className={styles.closeBtn} onClick={onClose}>
            <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
              <line x1="18" y1="6" x2="6" y2="18" />
              <line x1="6" y1="6" x2="18" y2="18" />
            </svg>
          </button>
        </div>

        {/* Body */}
        <div className={styles.body}>
          {/* List View */}
          {view === 'list' && (
            <>
              <div className={styles.actions}>
                <button className={styles.actionBtn} onClick={() => setView('upload')}>
                  + 上传新角色
                </button>
              </div>

              {loading ? (
                <div className={styles.empty}>加载中...</div>
              ) : groups.length === 0 ? (
                <div className={styles.empty}>暂无素材，点击上方按钮上传</div>
              ) : (
                <div className={styles.grid}>
                  {groups.map((group) => (
                    <div key={group.id} className={styles.card} onClick={() => handleGroupClick(group)}>
                      {group.asset_count === 0 ? (
                        <div className={styles.cardThumb} style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--color-text-disabled)', fontSize: 12 }}>暂无图片</div>
                      ) : (
                        <img src={tosThumb(group.thumbnail_url, 300)} alt={group.name} className={styles.cardThumb} />
                      )}
                      <div className={styles.cardInfo}>
                        {editingName && editingName.id === group.id ? (
                          <div className={styles.inlineEditWrap} onClick={(e) => e.stopPropagation()}>
                            <input
                              className={styles.inlineInput}
                              value={editingName.value}
                              onChange={(e) => setEditingName({ ...editingName, value: e.target.value })}
                              onKeyDown={(e) => {
                                if (e.key === 'Enter') handleRenameGroup(group.id, editingName.value);
                                if (e.key === 'Escape') setEditingName(null);
                              }}
                              autoFocus
                            />
                            <button
                              className={styles.editBtn}
                              onClick={() => handleRenameGroup(group.id, editingName.value)}
                              style={{ fontSize: 12, padding: '4px 10px', whiteSpace: 'nowrap' }}
                            >
                              保存
                            </button>
                            <button
                              className={styles.editBtn}
                              onClick={() => setEditingName(null)}
                              style={{ fontSize: 12, padding: '4px 10px', whiteSpace: 'nowrap' }}
                            >
                              取消
                            </button>
                          </div>
                        ) : (
                          <>
                            <span className={styles.cardName}>{group.name}</span>
                            <button
                              className={styles.editBtn}
                              onClick={(e) => {
                                e.stopPropagation();
                                setEditingName({ id: group.id, value: group.name });
                              }}
                            >
                              &#9998;
                            </button>
                          </>
                        )}
                      </div>
                    </div>
                  ))}
                </div>
              )}

              {totalPages > 1 && (
                <div className={styles.pagination}>
                  <button
                    className={styles.pageBtn}
                    disabled={page <= 1}
                    onClick={() => loadGroups(page - 1)}
                  >
                    上一页
                  </button>
                  <span className={styles.pageInfo}>{page} / {totalPages}</span>
                  <button
                    className={styles.pageBtn}
                    disabled={page >= totalPages}
                    onClick={() => loadGroups(page + 1)}
                  >
                    下一页
                  </button>
                </div>
              )}
            </>
          )}

          {/* Detail View */}
          {view === 'detail' && selectedGroup && (
            <>
              <div className={styles.actions}>
                <button
                  className={styles.actionBtnOutline}
                  onClick={() => setEditingName({ id: selectedGroup.id, value: selectedGroup.name })}
                >
                  &#9998; 改名
                </button>
              </div>

              {editingName && editingName.id === selectedGroup.id && (
                <div style={{ display: 'flex', gap: 8, marginBottom: 16, alignItems: 'center' }}>
                  <input
                    className={styles.textInput}
                    style={{ flex: 1 }}
                    value={editingName.value}
                    onChange={(e) => setEditingName({ ...editingName, value: e.target.value })}
                    onKeyDown={(e) => {
                      if (e.key === 'Enter') handleRenameGroup(selectedGroup.id, editingName.value);
                      if (e.key === 'Escape') setEditingName(null);
                    }}
                    autoFocus
                  />
                  <button
                    className={styles.actionBtn}
                    onClick={() => handleRenameGroup(selectedGroup.id, editingName.value)}
                    style={{ fontSize: 12, padding: '4px 10px', whiteSpace: 'nowrap' }}
                  >
                    保存
                  </button>
                  <button
                    className={styles.actionBtnOutline}
                    onClick={() => setEditingName(null)}
                    style={{ fontSize: 12, padding: '4px 10px', whiteSpace: 'nowrap' }}
                  >
                    取消
                  </button>
                </div>
              )}

              {/* ── 按类型分区显示 ── */}
              {(['Image', 'Video', 'Audio'] as const).map((assetType) => {
                const typeAssets = groupAssets.filter((a) => (a.asset_type || 'Image') === assetType);
                const typeLabel = assetType === 'Image' ? '肖像（图片）' : assetType === 'Video' ? '视频' : '音频';
                const acceptMap = { Image: 'image/*', Video: 'video/mp4,video/quicktime', Audio: 'audio/mpeg,audio/wav' };
                const hintMap = {
                  Image: '支持 JPG、PNG、WEBP、HEIC，单张不超过 30MB',
                  Video: '支持 MP4、MOV，单个不超过 50MB',
                  Audio: '支持 MP3、WAV，单个不超过 15MB',
                };
                const warningMap = {
                  Image: '⚠️ 宽高 300~6000 像素，宽高比 0.4~2.5',
                  Video: '⚠️ 时长 2~15 秒，宽高 300~6000 像素，帧率 24~60 FPS',
                  Audio: '⚠️ 时长 2~15 秒',
                };
                return (
                  <div key={assetType} style={{ marginBottom: 20 }}>
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 4 }}>
                      <span style={{ fontSize: 13, fontWeight: 600, color: 'var(--color-text-primary)' }}>{typeLabel}</span>
                      <label className={styles.actionBtn} style={{ cursor: 'pointer', fontSize: 12, padding: '3px 10px' }}>
                        + 追加
                        <input
                          type="file"
                          accept={acceptMap[assetType]}
                          style={{ display: 'none' }}
                          onChange={(e) => {
                            const file = e.target.files?.[0];
                            if (file) handleAddAsset(file);
                            e.target.value = '';
                          }}
                        />
                      </label>
                    </div>
                    <div style={{ fontSize: 11, color: 'var(--color-text-disabled)', marginBottom: 2 }}>{hintMap[assetType]}</div>
                    <div style={{ fontSize: 11, color: '#e8952e', marginBottom: 8 }}>{warningMap[assetType]}</div>
                    {typeAssets.length === 0 ? (
                      <div style={{ fontSize: 12, color: 'var(--color-text-disabled)', padding: '12px 0' }}>暂无，点击上方按钮上传</div>
                    ) : (
                      <div className={styles.assetGrid}>
                        {typeAssets.map((asset) => (
                          <div key={asset.id} className={styles.assetCard}>
                            {assetType === 'Video' ? (
                              <video src={asset.url} className={styles.assetThumb} muted preload="metadata" />
                            ) : assetType === 'Audio' ? (
                              <div className={styles.assetThumb} style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 32, background: '#1a1a2e' }}>♫</div>
                            ) : (
                              <img
                                src={tosThumb(asset.url, 300)}
                                alt={asset.name}
                                className={styles.assetThumb}
                                style={{ cursor: 'zoom-in' }}
                                onClick={() => setLightboxSrc(asset.url)}
                              />
                            )}
                            <button
                              className={styles.assetDeleteBtn}
                              onClick={(e) => {
                                e.stopPropagation();
                                if (confirm('确认删除此素材？删除后无法恢复。')) {
                                  assetsApi.deleteAsset(asset.id).then(() => {
                                    showToast('素材已删除');
                                    if (selectedGroup) {
                                      assetsApi.getGroupDetail(selectedGroup.id).then(({ data }) => {
                                        setGroupAssets(data.assets || []);
                                      });
                                    }
                                    loadGroups(page);
                                  }).catch(() => showToast('删除失败，请重试'));
                                }
                              }}
                              title="删除素材"
                            >×</button>
                            <div className={styles.assetInfo}>
                              <div className={styles.assetName}>{asset.name}</div>
                              <span
                                className={`${styles.statusBadge} ${
                                  asset.status === 'active' ? styles.statusActive
                                  : asset.status === 'processing' ? styles.statusProcessing
                                  : styles.statusFailed
                                }`}
                                title={asset.status === 'failed' ? (asset.error_message || '素材处理失败，请删除后重新上传') : undefined}
                              >
                                {asset.status === 'active' && '可用'}
                                {asset.status === 'processing' && '处理中'}
                                {asset.status === 'failed' && '失败'}
                              </span>
                            </div>
                          </div>
                        ))}
                      </div>
                    )}
                  </div>
                );
              })}
            </>
          )}

          {/* Upload View */}
          {view === 'upload' && (
            <div className={styles.uploadForm}>
              <div>
                <div className={styles.inputLabel}>角色名称</div>
                <input
                  className={styles.textInput}
                  placeholder="请输入角色名称，如：林峰"
                  maxLength={64}
                  value={newName}
                  onChange={(e) => setNewName(e.target.value)}
                />
              </div>

              <div>
                <div className={styles.inputLabel}>素材文件</div>
                <div
                  className={`${styles.dropZone} ${dragOver ? styles.dropZoneActive : ''}`}
                  onClick={() => fileInputRef.current?.click()}
                  onDragOver={(e) => { e.preventDefault(); setDragOver(true); }}
                  onDragLeave={() => setDragOver(false)}
                  onDrop={handleDrop}
                >
                  {uploadFile ? (
                    <>
                      {uploadPreview ? (
                        <img src={uploadPreview} alt="预览" className={styles.dropZonePreview} />
                      ) : (
                        <div style={{ fontSize: 32, padding: '16px 0' }}>
                          {uploadFile.type.startsWith('video/') ? '🎬' : '♫'}
                        </div>
                      )}
                      <div className={styles.dropZoneHint}>{uploadFile.name}</div>
                      <div className={styles.dropZoneHint} style={{ color: 'var(--color-text-disabled)' }}>点击重新选择</div>
                    </>
                  ) : (
                    <>
                      <div className={styles.dropZoneText}>上传素材文件</div>
                      <div className={styles.dropZoneHint}>将素材拖拽到这里，或点击选择文件</div>
                      <div className={styles.dropZoneHint}>支持图片(JPG/PNG/WEBP/HEIC)、视频(MP4/MOV)、音频(MP3/WAV)</div>
                    </>
                  )}
                  <div className={styles.dropZoneWarning}>⚠️ 图片：宽高 300~6000px，比例 0.4~2.5</div>
                  <div className={styles.dropZoneWarning}>⚠️ 视频：2~15秒，≤50MB | 音频：2~15秒，≤15MB</div>
                </div>
                <input
                  ref={fileInputRef}
                  type="file"
                  accept="image/*,video/mp4,video/quicktime,audio/mpeg,audio/wav"
                  style={{ display: 'none' }}
                  onChange={(e) => {
                    const file = e.target.files?.[0];
                    if (file) handleFileSelect(file);
                    e.target.value = '';
                  }}
                />
              </div>

              <button
                className={styles.submitBtn}
                disabled={!newName.trim() || !uploadFile || uploading}
                onClick={handleUploadSubmit}
              >
                {uploading ? '上传中...' : '确认上传'}
              </button>
            </div>
          )}
        </div>
      </div>
      <ImageLightbox src={lightboxSrc} onClose={() => setLightboxSrc(null)} />
    </div>
  );
}
