import { useState } from 'react';
import { open } from '@tauri-apps/plugin-dialog';
import { batchMatch, matchMaterial } from '../../../api/modules/materials';
import { toast } from '../../../store/uiStore';
import { computeAssignedIntervals } from '../utils/videoTimeline';
import { validateLocalVideo } from '../utils/videoValidation';
import type { ScriptShot } from '../../../types/project';

export interface UseEmptyShotMaterialsResult {
  materialMatchMap: Record<string, { url: string; duration: number } | null>;
  userUploadedMaterials: Record<string, { path: string; duration: number }>;
  matchMaterials: () => Promise<void>;
  matchSingleMaterial: (shotId: string) => Promise<{ url: string; duration: number } | null>;
  switchMaterial: (shotId: string) => Promise<{ url: string; duration: number } | null>;
  uploadMaterial: (shotId: string) => Promise<{ path: string; duration: number } | null>;
  setMaterialMatchMap: React.Dispatch<
    React.SetStateAction<Record<string, { url: string; duration: number } | null>>
  >;
  setUserUploadedMaterials: React.Dispatch<
    React.SetStateAction<Record<string, { path: string; duration: number }>>
  >;
}

/**
 * 空镜素材管理 Hook
 * - 手动匹配空镜素材（调用后端批量接口）
 * - 支持手动切换素材
 * - 支持上传本地素材
 */
export function useEmptyShotMaterials(
  shots: ScriptShot[],
  projectId: string | null
): UseEmptyShotMaterialsResult {
  const [materialMatchMap, setMaterialMatchMap] = useState<
    Record<string, { url: string; duration: number } | null>
  >({});
  const [userUploadedMaterials, setUserUploadedMaterials] = useState<
    Record<string, { path: string; duration: number }>
  >({});

  /**
   * 手动匹配空镜素材（调用后端批量接口）
   */
  const matchMaterials = async () => {
    const emptyShots = shots.filter((s) => s.type === 'empty_shot' && s.scene);
    if (emptyShots.length === 0) {
      setMaterialMatchMap({});
      return;
    }

    const newMap: Record<string, { url: string; duration: number } | null> = {};
    const assignedMap = computeAssignedIntervals(shots);

    // 收集需要调用 API 匹配的 shots（排除用户上传和已有空镜的）
    const apiScenes: Array<{ scene: string; duration: number }> = [];
    const apiShotIds: string[] = [];

    for (const shot of emptyShots) {
      const sid = String(shot.id);
      // 优先保留用户上传的素材
      const userMaterial = userUploadedMaterials[sid];
      if (userMaterial) {
        newMap[sid] = { url: userMaterial.path, duration: userMaterial.duration };
        continue;
      }
      // 已有匹配结果（来自上次视频生成后的保存），直接复用
      if (shot.emptyShotMaterial) {
        newMap[sid] = shot.emptyShotMaterial;
        continue;
      }
      const assigned = assignedMap[shot.id];
      const requiredDuration = (assigned.assignedEnd - assigned.assignedStart) / 1000;
      apiScenes.push({ scene: shot.scene || '', duration: requiredDuration });
      apiShotIds.push(sid);
    }

    // 批量匹配（后端通过 Redis 自动做项目级去重）
    if (apiScenes.length > 0) {
      try {
        const batchResult = await batchMatch(apiScenes, projectId || undefined);
        for (let i = 0; i < apiShotIds.length; i++) {
          newMap[apiShotIds[i]] = batchResult.results[i] ?? null;
        }
      } catch (err) {
        console.error('[VideoGeneration] 批量素材匹配失败:', err);
        toast.error(err instanceof Error ? err.message : '素材匹配失败');
        for (const sid of apiShotIds) {
          newMap[sid] = null;
        }
      }
    }

    setMaterialMatchMap(newMap);
    // 匹配结果仅作为组件本地状态，视频生成成功后再统一持久化到 segments.json
  };

  /**
   * 单个镜头素材匹配
   * @returns 匹配结果或 null
   */
  const matchSingleMaterial = async (
    shotId: string
  ): Promise<{ url: string; duration: number } | null> => {
    const shot = shots.find((s) => String(s.id) === shotId);
    if (!shot || shot.type !== 'empty_shot' || !shot.scene) {
      return null;
    }

    const assignedMap = computeAssignedIntervals(shots);
    const assigned = assignedMap[shot.id];
    const requiredDuration = (assigned.assignedEnd - assigned.assignedStart) / 1000;

    try {
      const result = await matchMaterial(shot.scene || '', requiredDuration, projectId || undefined);
      setMaterialMatchMap((prev) => ({
        ...prev,
        [shotId]: result || null,
      }));
      if (!result) {
        toast.warning('暂无可用素材');
      }
      return result;
    } catch (err) {
      console.error('[VideoGeneration] 素材匹配失败:', err);
      toast.error(err instanceof Error ? err.message : '素材匹配失败');
      setMaterialMatchMap((prev) => ({ ...prev, [shotId]: null }));
      return null;
    }
  };

  /**
   * 切换空镜素材（换一个）
   * 返回新素材信息，由调用方决定是否刷新预览
   */
  const switchMaterial = async (shotId: string): Promise<{ url: string; duration: number } | null> => {
    const shot = shots.find((s) => String(s.id) === shotId);
    if (!shot) {
      return null;
    }

    try {
      const assignedMap = computeAssignedIntervals(shots);
      const assigned = assignedMap[shot.id];
      const requiredDuration = (assigned.assignedEnd - assigned.assignedStart) / 1000;
      const result = await matchMaterial(shot.scene || '', requiredDuration, projectId || undefined);

      // 清除用户上传标记（如果有）
      if (userUploadedMaterials[shotId]) {
        const next = { ...userUploadedMaterials };
        delete next[shotId];
        setUserUploadedMaterials(next);
      }

      setMaterialMatchMap((prev) => ({
        ...prev,
        [shotId]: result || prev[shotId],
      }));

      if (result) {
        toast.success('已更换素材');
      } else {
        toast.warning('暂无其他可用素材');
      }
      return result;
    } catch (err) {
      console.error('[VideoGeneration] 切换素材失败:', err);
      toast.error('切换素材失败');
      return null;
    }
  };

  /**
   * 选择空镜素材（直接使用本地文件路径）
   * 返回上传的素材信息，由调用方决定是否刷新预览
   */
  const uploadMaterial = async (shotId: string): Promise<{ path: string; duration: number } | null> => {
    try {
      const selected = await open({
        multiple: false,
        filters: [{ name: 'Video', extensions: ['mp4', 'mov'] }],
      });
      if (!selected || Array.isArray(selected)) {
        return null;
      }

      // 根据空镜实际分配时长计算最小要求
      const shot = shots.find((s) => String(s.id) === shotId);
      if (!shot) {
        toast.error('镜头不存在');
        return null;
      }
      const assignedMap = computeAssignedIntervals(shots);
      const assigned = assignedMap[shot.id];
      const requiredDuration = (assigned.assignedEnd - assigned.assignedStart) / 1000;
      const minDuration = Math.max(requiredDuration, 1);

      const result = await validateLocalVideo(selected, {
        minDuration,
        maxDuration: 20,
        requireResolution: true,
      });
      if (!result.valid) {
        toast.error(result.error || '视频验证失败');
        return null;
      }

      const duration = parseFloat(result.duration.toFixed(1));
      const material = { path: selected, duration };
      setUserUploadedMaterials((prev) => ({ ...prev, [shotId]: material }));
      setMaterialMatchMap((prev) => ({ ...prev, [shotId]: { url: selected, duration } }));

      toast.success('素材设置成功');
      return material;
    } catch (e) {
      console.error('[VideoGeneration] 设置素材失败:', e);
      toast.error('设置素材失败');
      return null;
    }
  };

  return {
    materialMatchMap,
    userUploadedMaterials,
    matchMaterials,
    matchSingleMaterial,
    switchMaterial,
    uploadMaterial,
    setMaterialMatchMap,
    setUserUploadedMaterials,
  };
}
