import { useState, useCallback, useMemo, useEffect, useRef } from 'react';
import { scriptApi, ScriptShot, CategoryItem } from '../../api/modules/script';
import { createTask, getTaskStatus } from '../../api/modules/task';
import { adaptScriptShots } from '../../api/adapters/scriptAdapter';
import { useProjectStore, usePointStore } from '../../store';
import { toast } from '../../store/uiStore';
import { useProgressStore } from '../../store/progressStore';
import { ShotStats } from '../../components/ShotStats';
import ConfirmModal from '../../components/Modal/ConfirmModal';
import { usePointsCheck } from '../../hooks/usePointsCheck';
import { getFriendlyErrorMessage } from '../../utils/errorMessage';
import './ScriptCreation.css';



/**
 * 脚本生成页面
 */
export default function ScriptCreation() {
  // 使用 selector 模式订阅 store，确保组件正确响应状态变化
  const segments = useProjectStore(state => state.segments);
  const setSegments = useProjectStore(state => state.setSegments);
  const markStepsDirty = useProjectStore(state => state.markStepsDirty);
  const updateSegment = useProjectStore(state => state.updateSegment);
  const categoryCode = useProjectStore(state => state.categoryCode);
  const filename = useProjectStore(state => state.filename);
  const setTopic = useProjectStore(state => state.setTopic);
  const setCategoryCode = useProjectStore(state => state.setCategoryCode);
  const setFilename = useProjectStore(state => state.setFilename);

  const [generating, setGenerating] = useState(false);
  const requestLock = useRef(false);

  // 分类列表（从后端动态加载）
  const [categories, setCategories] = useState<CategoryItem[]>([]);
  // 选中的大类和文件名
  const [selectedCategory, setSelectedCategory] = useState<string>(categoryCode || '');
  const [selectedFilename, setSelectedFilename] = useState<string>(filename || '');

  // 加载分类列表（带本地缓存 + 静默刷新）
  useEffect(() => {
    const { cached, refresh } = scriptApi.getCategoriesCached();
    if (cached) {
      setCategories(cached);
    }
    refresh
      .then(data => {
        setCategories(data);
      })
      .catch((err: Error) => {
        console.error('[分类加载失败]', err);
        if (!cached) {
          // 始终显示详细错误，方便跨平台诊断（Windows WebView2 网络问题需要具体信息）
          toast.error(`加载分类列表失败: ${err.message}`);
        }
      });
  }, []);

  // 分类列表加载后，恢复之前保存的选中状态
  useEffect(() => {
    if (categories.length === 0) {return;}
    if (categoryCode && filename) {
      // 验证保存的文件名是否在当前分类列表中有效
      const catExists = categories.some(c => c.code === categoryCode);
      const fileExists = categories.some(c =>
        c.code === categoryCode && c.files.some(f => f.filename === filename)
      );
      if (catExists && fileExists) {
        setSelectedCategory(categoryCode);
        setSelectedFilename(filename);
      }
    }
  }, [categories, categoryCode, filename]);

  // 编辑状态：存储正在编辑的字段键（如 "1-scene", "2-voiceover"）
  const [editingFields, setEditingFields] = useState<Set<string>>(new Set());

  // 润色状态
  const [polishingState, setPolishingState] = useState<{
    id: number;
    type: 'scene' | 'prompt' | 'voiceover';
  } | null>(null);

  // 展开/收起状态
  const [expandedSegments, setExpandedSegments] = useState<Set<number>>(new Set());
  // 标记是否已初始化展开状态（防止收起后被 useEffect 重新展开）
  const hasInitExpandedRef = useRef(false);

  // 重新生成确认弹窗
  const [showRegenerateConfirm, setShowRegenerateConfirm] = useState(false);

  const shots = useMemo(() => segments || [], [segments]);
  const generated = shots.length > 0;

  // 检测是否已有后续步骤数据
  const hasSubsequentData = useMemo(() => {
    return shots.some(s => s.videoPath || s.alignmentResult || s.burnedVideoPath);
  }, [shots]);

  // 首次有脚本内容时默认展开所有镜头（只执行一次，不覆盖用户手动收起）
  useEffect(() => {
    if (!hasInitExpandedRef.current && segments.length > 0) {
      hasInitExpandedRef.current = true;
      setExpandedSegments(new Set(segments.map(s => s.id)));
    }
  }, [segments]);

  // 使用 useMemo 缓存统计计算，避免每次渲染重复计算
  const stats = useMemo(
    () => ({
      totalWords: shots.reduce(
        (a, s) => a + (typeof s.voiceover === 'string' ? s.voiceover.length : 0),
        0
      ),
      totalDuration: shots.reduce((a, s) => {
        const durationStr = typeof s.duration === 'string' ? s.duration : '5s';
        const seconds = parseFloat(durationStr.replace(/[^0-9.]/g, '') || '0');
        return a + seconds;
      }, 0),
      segmentCount: shots.filter(s => s.type !== 'empty_shot').length,
      emptyShotCount: shots.filter(s => s.type === 'empty_shot').length,
    }),
    [shots]
  );

  // stats 直接传递给 ShotStats 组件，无需解构

  /**
   * 轮询任务状态直到完成或失败
   */
  const pollTask = async (taskId: string, onProgress: (msg: string) => void): Promise<unknown> => {
    const interval = 2000; // 2 秒
    const timeout = 300_000; // 5 分钟
    const start = Date.now();

    while (Date.now() - start < timeout) {
      const status = await getTaskStatus(taskId);
      onProgress(status.message || `进度 ${status.progress}%`);

      if (status.status === 'completed') {
        return status.result;
      }
      if (status.status === 'failed') {
        throw new Error(status.error || '任务执行失败');
      }
      // pending / running / waiting 继续轮询
      await new Promise(r => setTimeout(r, interval));
    }

    throw new Error('任务超时，请稍后到任务列表查看结果');
  };

  /**
   * 执行生成脚本（异步任务 + 轮询）
   */
  const doGenerate = async () => {
    if (!selectedCategory || !selectedFilename) {
      toast.warning('请选择创作主题');
      return;
    }

    // 前置积分检查：脚本生成
    const scriptPoints = usePointStore.getState().getRule('script')?.points || 5;
    const ok = await checkBalance(scriptPoints, '脚本生成');
    if (!ok) {return;}

    // 请求去重锁：防止网络延迟期间快速点击发起多个请求
    if (requestLock.current) {
      return;
    }
    requestLock.current = true;

    setGenerating(true);
    const progress = useProgressStore.getState();
    progress.show('脚本生成');

    try {
      // 1. 创建异步任务
      const { taskId } = await createTask('script', {
        category: selectedCategory,
        filename: selectedFilename,
      });

      // 2. 轮询任务状态
      const result = await pollTask(taskId, (msg) => progress.update(msg));

      if (!result) {
        progress.error('任务结果为空');
        return;
      }

      // 3. 解析结果：异步任务返回 { title, scenes, total_duration, style, shot_count }
      const resultObj = result as Record<string, unknown>;
      const scenes = resultObj.scenes as ScriptShot[] | undefined;

      if (!scenes || scenes.length === 0) {
        progress.error('生成分镜为空');
        return;
      }

      let normalizedShots: ScriptShot[];
      try {
        normalizedShots = adaptScriptShots(scenes);
      } catch (e) {
        console.error('[ScriptCreation] 数据适配失败:', e, '原始数据:', scenes);
        progress.error('数据解析失败');
        return;
      }

      if (normalizedShots.length === 0) {
        progress.error('生成分镜为空');
        return;
      }

      setSegments(normalizedShots);
      setExpandedSegments(new Set(normalizedShots.map(s => s.id)));
      markStepsDirty(1);
      progress.success('脚本生成成功', scriptPoints);

      // 设置标题
      const title = typeof resultObj.title === 'string' ? resultObj.title : '';
      if (title) {
        setTopic(title);
      }
    } catch (error) {
      if (handleError(error, '脚本生成', 5)) {
        progress.hide();
        return;
      }
      progress.error(getFriendlyErrorMessage(error, '脚本生成失败，请稍后重试'));
    } finally {
      requestLock.current = false;
      setGenerating(false);
    }
  };

  /**
   * 生成脚本入口（带确认弹窗）
   */
  const handleGenerate = () => {
    if (hasSubsequentData) {
      setShowRegenerateConfirm(true);
      return;
    }
    doGenerate();
  };

  /**
   * 切换字段编辑状态
   */
  const toggleEditField = useCallback((id: number, field: 'scene' | 'prompt' | 'voiceover') => {
    const key = `${id}-${field}`;
    setEditingFields(prev => {
      const next = new Set(prev);
      if (next.has(key)) {
        next.delete(key);
      } else {
        next.add(key);
      }
      return next;
    });
  }, []);

  /**
   * 处理字段更新
   */
  const handleFieldChange = useCallback(
    (id: number, field: 'scene' | 'prompt' | 'voiceover' | 'duration', value: string) => {
      if (field === 'duration') {
        const actualDuration = parseFloat(value.replace(/[^0-9.]/g, '')) || 5;
        updateSegment(id, { [field]: value, actualDuration });
      } else {
        updateSegment(id, { [field]: value });
      }
    },
    [updateSegment]
  );

  /**
   * 切换分镜展开/收起
   */
  const toggleExpand = useCallback((id: number) => {
    setExpandedSegments(prev => {
      const next = new Set(prev);
      if (next.has(id)) {
        next.delete(id);
      } else {
        next.add(id);
      }
      return next;
    });
  }, []);

  /**
   * 展开所有镜头
   */
  const expandAll = useCallback(() => {
    setExpandedSegments(new Set(shots.map(s => s.id)));
  }, [shots]);

  /**
   * 收起所有镜头
   */
  const collapseAll = useCallback(() => {
    setExpandedSegments(new Set());
  }, []);

  // 字段编辑的key生成函数
  /**
   * 处理润色
   */
  const { checkBalance, handleError, PointsModal } = usePointsCheck();

  const handlePolish = async (
    id: number,
    content: string,
    type: 'scene' | 'prompt' | 'voiceover'
  ) => {
    // 前置积分检查：润色
    const polishPoints = usePointStore.getState().getRule('polish')?.points || 1;
    const ok = await checkBalance(polishPoints, type === 'voiceover' ? '文案润色' : '画面润色');
    if (!ok) {return;}

    setPolishingState({ id, type });
    try {
      // 后端润色接口：scene=画面描述, voiceover=配音文本
      const polishType = type === 'scene' || type === 'prompt' ? 'scene' : 'voiceover';
      // 获取当前镜头的类型（分镜/空镜）
      const shot = shots.find(s => s.id === id);
      const shotType = shot?.type === 'empty_shot' ? 'empty_shot' : 'segment';
      const result = await scriptApi.polish(id, content, polishType, shotType);
      handleFieldChange(id, type, result);
    } catch (error) {
      if (handleError(error, type === 'voiceover' ? '文案润色' : '画面润色', 1)) {return;}
      console.error('润色失败:', error);
      toast.error('润色失败，请重试');
    } finally {
      setPolishingState(null);
    }
  };

  return (
    <div className="step-layout script-creation">
      {/* Left Panel - 参数配置 */}
      <div className="step-panel-left">
        {/* 创作主题 */}
        <div className="panel-section">
          <label className="panel-label">创作主题</label>
          {categories.map((cat) => (
            <div key={cat.code}>
              <div className="topic-groups">
                {cat.files.map((file) => (
                  <button
                    key={file.filename}
                    className={`option-card ${selectedCategory === cat.code && selectedFilename === file.filename ? 'selected' : ''}`}
                    onClick={() => {
                      setSelectedCategory(cat.code);
                      setSelectedFilename(file.filename);
                      setTopic(file.label);
                      setCategoryCode(cat.code);
                      setFilename(file.filename);
                    }}
                    title={file.desc}
                  >
                    <div className="option-card-label">{file.label}</div>
                    <div className="option-card-desc">{file.desc}</div>
                  </button>
                ))}
              </div>
            </div>
          ))}
        </div>

        {/* 生成按钮 */}
        <button
          className="btn btn-primary"
          style={{ width: '100%' }}
          onClick={handleGenerate}
          disabled={generating}
        >
          {generated ? `重新生成脚本（${usePointStore.getState().getRule('script')?.points || 5} 积分）` : `生成脚本（${usePointStore.getState().getRule('script')?.points || 5} 积分）`}
        </button>

        {/* 生成进度由全局 ProgressModal 统一展示 */}
      </div>

      {/* Right Panel - 分镜编辑 */}
      <div className="step-panel-right">
        {generated ? (
          <div className="script-editor">
            {/* 统计和操作栏 */}
            <div className="script-editor-header">
              <label className="panel-label">脚本分镜</label>
              <div className="script-editor-actions">
                <button className="btn btn-ghost btn-sm" onClick={expandAll}>
                  展开全部
                </button>
                <button className="btn btn-ghost btn-sm" onClick={collapseAll}>
                  收起全部
                </button>
              </div>
            </div>

            {/* 🆕 使用通用 ShotStats 组件 */}
            <ShotStats stats={stats} />

            {/* 镜头列表 */}
            {shots.map(seg => {
              const isEmptyShot = seg.type === 'empty_shot';
              return (
                <div
                  key={seg.id}
                  className={`script-segment ${expandedSegments.has(seg.id) ? 'expanded' : ''}`}
                >
                  <div className="segment-header" onClick={() => toggleExpand(seg.id)}>
                    <div className="segment-title-group">
                      <span className="segment-title">
                        {`镜头 ${seg.id}`}
                        <span
                          className="shot-type-badge"
                          style={{
                            backgroundColor: 'rgba(34, 197, 94, 0.15)',
                            color: 'rgb(34, 197, 94)',
                            marginLeft: '8px',
                            fontSize: '10px',
                            padding: 'var(--spacing-2xs) var(--spacing-xs)',
                            borderRadius: '4px',
                            fontWeight: 600,
                          }}
                        >
                          {isEmptyShot ? '空镜' : '分镜'}
                        </span>
                      </span>
                      <span className="segment-duration">
                        {typeof seg.duration === 'string' ? seg.duration : '5s'}
                      </span>
                    </div>
                    <div className="segment-header-actions">
                      {/* 展开/收起指示器 */}
                      <span className="expand-indicator">
                        {expandedSegments.has(seg.id) ? (
                          <svg
                            width="16"
                            height="16"
                            viewBox="0 0 24 24"
                            fill="none"
                            stroke="currentColor"
                            strokeWidth="2"
                          >
                            <polyline points="18 15 12 9 6 15" />
                          </svg>
                        ) : (
                          <svg
                            width="16"
                            height="16"
                            viewBox="0 0 24 24"
                            fill="none"
                            stroke="currentColor"
                            strokeWidth="2"
                          >
                            <polyline points="6 9 12 15 18 9" />
                          </svg>
                        )}
                      </span>
                    </div>
                  </div>

                  {expandedSegments.has(seg.id) && (
                    <div className="segment-body">
                      {/* 画面描述（分镜：scene，空镜：prompt）—— 只读 */}
                      <div className="segment-field">
                        <div className="segment-field-header">
                          <span className="segment-field-label">画面描述</span>
                        </div>
                        <p className="segment-field-value">
                          {typeof seg.scene === 'string' ? seg.scene : '未设置画面描述'}
                        </p>
                      </div>

                      {/* 配音文本/画外音（两种类型都有） */}
                      <div className="segment-field">
                        <div className="segment-field-header">
                          <span className="segment-field-label">配音文本</span>
                          <div className="segment-field-actions">
                            <button
                              className="btn btn-ghost btn-xs"
                              disabled={!!polishingState}
                              onClick={() =>
                                handlePolish(
                                  seg.id,
                                  typeof seg.voiceover === 'string' ? seg.voiceover : '',
                                  'voiceover'
                                )
                              }
                            >
                              {polishingState?.id === seg.id && polishingState?.type === 'voiceover' ? (
                                <svg
                                  width="12"
                                  height="12"
                                  viewBox="0 0 24 24"
                                  fill="none"
                                  stroke="currentColor"
                                  strokeWidth="2"
                                  style={{ animation: 'spin 1s linear infinite' }}
                                >
                                  <path d="M21 12a9 9 0 11-6.219-8.56" />
                                </svg>
                              ) : null}
                              润色
                            </button>
                            <button
                              className="btn btn-ghost btn-xs"
                              onClick={() => toggleEditField(seg.id, 'voiceover')}
                            >
                              {editingFields.has(`${seg.id}-voiceover`) ? '完成' : '编辑'}
                            </button>
                          </div>
                        </div>
                        {editingFields.has(`${seg.id}-voiceover`) ? (
                          <textarea
                            value={typeof seg.voiceover === 'string' ? seg.voiceover : ''}
                            onChange={e => handleFieldChange(seg.id, 'voiceover', e.target.value)}
                            rows={3}
                            autoFocus
                            placeholder="输入配音文本..."
                          />
                        ) : (
                          <p
                            className="segment-field-value"
                            onClick={() => toggleEditField(seg.id, 'voiceover')}
                            style={{ minHeight: '60px' }}
                          >
                            {typeof seg.voiceover === 'string' ? (
                              seg.voiceover || (
                                <span
                                  style={{ color: 'var(--text-tertiary)', fontStyle: 'italic' }}
                                >
                                  点击编辑文案...
                                </span>
                              )
                            ) : (
                              <span style={{ color: 'var(--text-tertiary)', fontStyle: 'italic' }}>
                                点击编辑文案...
                              </span>
                            )}
                          </p>
                        )}
                      </div>
                    </div>
                  )}
                </div>
              );
            })}
          </div>
        ) : (
          <div className="empty-state">
            <div className="empty-state-icon">
              <svg
                width="48"
                height="48"
                viewBox="0 0 24 24"
                fill="none"
                stroke="currentColor"
                strokeWidth="1"
                strokeLinecap="round"
                strokeLinejoin="round"
              >
                <path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z" />
                <polyline points="14 2 14 8 20 8" />
                <line x1="16" y1="13" x2="8" y2="13" />
                <line x1="16" y1="17" x2="8" y2="17" />
                <polyline points="10 9 9 9 8 9" />
              </svg>
            </div>
            <p className="empty-state-title">暂无脚本内容</p>
            <p className="empty-state-desc">
              在左侧选择创作主题后点击{'"'}生成脚本{'"'}
            </p>
          </div>
        )}
      </div>

      <ConfirmModal
        open={showRegenerateConfirm}
        onClose={() => setShowRegenerateConfirm(false)}
        onConfirm={() => {
          setShowRegenerateConfirm(false);
          doGenerate();
        }}
        onCancel={() => setShowRegenerateConfirm(false)}
        type="warning"
        title="重新生成脚本"
        description={
          '该操作将覆盖视频、字幕等现有数据，\n' +
          '且消费积分不返还。是否继续？'
        }
        confirmText="继续生成"
        cancelText="取消"
        confirmButtonType="danger"
      />
      <PointsModal />
    </div>
  );
}
