// ============================================================
// OutputPreview — 任务输出预览（图片 / 视频）
// 使用 useTaskDetail() Hook 获取任务详情，组件仅负责渲染
//
// 媒体加载策略：
//   - <img>/<video> 直接加载远程 URL（无 CORS 限制，与 axios/fetch 不同）
//   - 类型检测：URL 扩展名正则 + output_type 补充（无扩展名 CDN 链接）
//   - 加载失败：<Image fallback> 显示占位图；<video onError> 静默（浏览器内置错误提示）
//
// 注意：CDN 签名过期（403 SignatureExpired）的 HTTP 级检测需要 CORS
// 响应头支持，当前 CDN 不具备。后续可通过主进程 Node.js HTTP（无 CORS）
// 实现精确检测。
// ============================================================

import { useMemo, useRef, useEffect, useCallback } from 'react';
import { Image, Empty, Spin, Typography, Button, Tag, theme as antTheme, App } from 'antd';
import {
   EyeOutlined,
   DownloadOutlined,
   CloseCircleOutlined,
} from '@ant-design/icons';

import { useHomeContext } from '@/modules/home/stores/HomeContext';
import { useTaskDetail } from '@/shared/hooks/use-api';
import { POLLING_STATUSES, type TaskStatusString } from '@/modules/home/controllers/task-api';
import { ContextMenu } from '@/shared/components/ContextMenu';
import { getPreviewImageMenu, getPreviewEmptyMenu } from '../../controllers/menus';

const { Text } = Typography;

// ---------- 状态标签配置 ----------

const STATUS_CONFIG: Record<TaskStatusString, { color: string; label: string }> = {
   pending: { color: 'blue', label: '排队中' },
   submitted: { color: 'cyan', label: '已提交' },
   processing: { color: 'orange', label: '处理中' },
   success: { color: 'green', label: '已完成' },
   failed: { color: 'red', label: '失败' },
};

// ---------- 工具函数 ----------

/**
 * 通过 URL 扩展名判断是否为视频。
 * 对 CDN 直连链接（无扩展名）返回 false，此时由 output_type 兜底。
 */
function isVideoUrl(url: string): boolean {
   return /\.(mp4|webm|mov|avi|mkv)(\?|$)/i.test(url);
}

/**
 * 分离图片/视频 URL。
 *
 * 策略（优先级从高到低）：
 *   1. URL 正则匹配（对带扩展名的链接精确识别）
 *   2. output_type 兜底（CDN 无扩展名链接）：
 *      - output_type='video' → 首个资产按视频处理，其余按图片
 *      - output_type='image' / 'audio' → 全部按图片处理
 */
function splitAssets(
   assets: Array<{ url: string }>,
   outputType?: string,
): { images: string[]; videos: string[] } {
   const images: string[] = [];
   const videos: string[] = [];

   assets.forEach(({ url }) => {
      if (isVideoUrl(url)) {
         videos.push(url);
      } else if (outputType === 'video' && videos.length === 0) {
         // CDN 无扩展名链接，由 output_type 提示首个为视频
         videos.push(url);
      } else {
         images.push(url);
      }
   });

   return { images, videos };
}

// ---------- 组件 ----------

export function OutputPreview() {
   const { token } = antTheme.useToken();
   const { message } = App.useApp();
   const { selectedTask } = useHomeContext();

   // 数据获取（Hook 自动处理：taskId 为 null 时不请求、竞态、loading/error）
   const { data: detail, loading, refetch } = useTaskDetail(selectedTask?.id);

   // ======== 状态转换监听：非终态→终态时触发详情刷新 ========
   const prevStatusRef = useRef<TaskStatusString | undefined>(undefined);

   useEffect(() => {
      const status = selectedTask?.status as TaskStatusString | undefined;
      const prev = prevStatusRef.current;

      if (
         prev &&
         POLLING_STATUSES.includes(prev) &&
         status &&
         !POLLING_STATUSES.includes(status)
      ) {
         refetch();
      }

      prevStatusRef.current = status;
   }, [selectedTask?.status, refetch]);

   // 按类型分类（URL 正则 + output_type 兜底）
   const { images, videos } = useMemo(() => {
      if (!detail?.output_assets || detail.output_assets.length === 0) {
         return { images: [], videos: [] };
      }
      return splitAssets(detail.output_assets, detail.output_type);
   }, [detail]);

   const status = selectedTask?.status as TaskStatusString | undefined;
   const statusCfg = status
      ? (STATUS_CONFIG[status] || { color: 'default', label: status })
      : { color: 'default', label: '未知' };

   // ── 右键菜单 ──
   const hasPreview = (images.length + videos.length) > 0;

   const handleOpenFileLocation = useCallback(() => {
       // 云端任务输出为 CDN URL，暂无本地路径概念
       message.info('云端任务输出无本地文件路径');
   }, [message]);

   const handleCopyImageToClipboard = useCallback(async () => {
       if (images.length > 0) {
           try {
               await navigator.clipboard.writeText(images[0]);
               message.success('已复制图片链接');
           } catch {
               message.error('复制失败');
           }
       }
   }, [images, message]);

   const handleOpenSavePath = useCallback(() => {
       message.info('打开保存路径功能待实现');
   }, [message]);

   const previewMenuItems = hasPreview
       ? getPreviewImageMenu({ hasPreview, onOpenFileLocation: handleOpenFileLocation, onCopyImageToClipboard: handleCopyImageToClipboard, onOpenSavePath: handleOpenSavePath })
       : getPreviewEmptyMenu({ hasPreview, onOpenFileLocation: handleOpenFileLocation, onCopyImageToClipboard: handleCopyImageToClipboard, onOpenSavePath: handleOpenSavePath });

   // ---- 无选中任务 ----
   if (!selectedTask) {
      return (
         <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%' }}>
            <Empty description="选择任务记录查看输出" image={Empty.PRESENTED_IMAGE_SIMPLE} />
         </div>
      );
   }

   // ---- 处理中 ----
   if (status && POLLING_STATUSES.includes(status)) {
      return (
         <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', gap: 16 }}>
            <Spin size="large" />
            <Tag color={statusCfg.color}>{statusCfg.label}</Tag>
            <Text type="secondary">任务正在处理中，请稍候...</Text>
         </div>
      );
   }

   // ---- 失败 ----
   if (status === 'failed') {
      return (
         <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', gap: 12 }}>
            <CloseCircleOutlined style={{ fontSize: 48, color: '#ff4d4f' }} />
            <Text type="danger" strong>任务执行失败</Text>
            {detail?.error_message && (
               <Text type="secondary" style={{ maxWidth: 300, textAlign: 'center', fontSize: 12 }}>
                  {detail.error_message}
               </Text>
            )}
         </div>
      );
   }

   // ---- 加载中（任务详情） ----
   if (loading) {
      return (
         <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%' }}>
            <Spin size="large" />
         </div>
      );
   }

   // ---- 无结果 ----
   if (!detail || (images.length + videos.length === 0)) {
      return (
         <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%' }}>
            <Empty description="暂无输出结果" image={Empty.PRESENTED_IMAGE_SIMPLE} />
         </div>
      );
   }

   // ---- 展示 ----
   return (
      <ContextMenu items={previewMenuItems}>
      <div style={{ height: '100%', display: 'flex', flexDirection: 'column', overflow: 'hidden' }}>
         <div style={{
            padding: '12px 16px',
            borderBottom: `1px solid ${token.colorBorderSecondary}`,
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'space-between',
            flexShrink: 0,
         }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
               <EyeOutlined style={{ fontSize: 14 }} />
               <Text strong style={{ fontSize: 13 }}>输出预览</Text>
               <Tag color={statusCfg.color} style={{ fontSize: 11 }}>{statusCfg.label}</Tag>
            </div>
            {videos.length > 0 && (
               <Button size="small" type="link" icon={<DownloadOutlined />} href={videos[0]} target="_blank">
                  下载视频
               </Button>
            )}
         </div>

         <div style={{ flex: 1, overflow: 'auto', padding: 12, display: 'flex', flexDirection: 'column', gap: 12 }}>
            {videos.map((url, i) => (
               <div key={i} style={{ borderRadius: 6, overflow: 'hidden', background: '#000' }}>
                  <video controls style={{ width: '100%', maxHeight: 360, display: 'block' }} src={url}
                     onError={() => console.debug('[OutputPreview] 视频加载失败:', url)}
                  >
                     您的浏览器不支持视频播放
                  </video>
               </div>
            ))}
            {images.length === 1 ? (
               <Image src={images[0]} alt="输出结果" style={{ borderRadius: 6, width: '100%', objectFit: 'contain' }}
                  fallback="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZjBmMGYwIi8+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGRvbWluYW50LWJhc2VsaW5lPSJtaWRkbGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiNjMGMwYzAiIGZvbnQtc2l6ZT0iMTQiPuWbvueJh+WKoOi9veWksei0pTwvdGV4dD48L3N2Zz4="
               />
            ) : (
               <Image.PreviewGroup>
                  {images.map((url, i) => (
                     <Image key={i} src={url} alt={`输出结果 ${i + 1}`}
                        style={{ borderRadius: 6, width: '100%', objectFit: 'contain', marginBottom: 8 }}
                        fallback="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZjBmMGYwIi8+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGRvbWluYW50LWJhc2VsaW5lPSJtaWRkbGUiIHRleHQtYW5jaG9yPSJtaWRkbGUiIGZpbGw9IiNjMGMwYzAiIGZvbnQtc2l6ZT0iMTQiPuWbvueJh+WKoOi9veWksei0pTwvdGV4dD48L3N2Zz4="
                     />
                  ))}
               </Image.PreviewGroup>
            )}
         </div>
      </div>
      </ContextMenu>
   );
}
