/**
 * 封面设计页面 (Step 5) - Fabric.js 版
 * ================================
 *
 * 使用 Fabric.js Canvas 实时预览封面：
 * - 背景图：点击卡片弹窗选图（6 张随机）
 * - 封面形象：点击卡片弹窗选人
 * - 模板：双标题居中
 * - 导出：PNG 高清导出
 */

import { useState, useEffect, useRef } from 'react';

interface FileWithPath extends File {
  path?: string;
}
import { useCoverAvatarStore } from '../../store';
import { invoke } from '@tauri-apps/api/core';
import { save } from '@tauri-apps/plugin-dialog';
import { useProjectStore } from '../../store';
import { getCurrentProjectId } from '../../api/modules/localStorage';
import { useCoverFabric } from '../../hooks/useCoverFabric';
import { useProgressStore } from '../../store/progressStore';
import { scriptApi } from '../../api/modules/script';
import { coverApi, CoverBackground } from '../../api/modules/cover';
import { pointsApi } from '../../api/modules/points';
import { usePointStore, useAuthStore } from '../../store';
import RechargeModal from '../../components/RechargeModal/RechargeModal';
import ConfirmModal from '../../components/Modal/ConfirmModal';
import Modal from '../../components/Modal/Modal';
import { toast } from '../../store/uiStore';
import { getFriendlyErrorMessage } from '../../utils/errorMessage';
import { usePointsCheck } from '../../hooks/usePointsCheck';
import './CoverDesign.css';

interface BgImage {
  id: string;
  src: string;
  name: string;
}

function shuffleArray<T>(arr: T[]): T[] {
  const result = [...arr];
  for (let i = result.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [result[i], result[j]] = [result[j], result[i]];
  }
  return result;
}

function pickSeven(all: BgImage[], lastIds: Set<string>): BgImage[] {
  if (all.length <= 7) {return shuffleArray(all);}
  let shuffled = shuffleArray(all);
  for (let i = 0; i < 10; i++) {
    const picked = shuffled.slice(0, 7);
    const pickedIds = new Set(picked.map((b) => b.id));
    const allSame =
      pickedIds.size === 7 &&
      lastIds.size === 7 &&
      [...pickedIds].every((id) => lastIds.has(id));
    if (!allSame) {return picked;}
    shuffled = shuffleArray(all);
  }
  return shuffled.slice(0, 7);
}

export default function CoverDesign() {
  const coverConfig = useProjectStore((state) => state.coverConfig);
  const coverPath = useProjectStore((state) => state.coverPath);
  const setCoverPath = useProjectStore((state) => state.setCoverPath);
  const setCoverConfig = useProjectStore((state) => state.setCoverConfig);
  const stepDirtyFlags = useProjectStore((state) => state.stepDirtyFlags);
  const isStepDirty = (stepDirtyFlags?.[5] ?? false) && !!coverPath;
  const projectId = getCurrentProjectId();

  const [config, setConfig] = useState<{
    template: 'dual-title';
    backgroundImage: string | null;
    mainTitle: string;
    subtitle: string;
    avatarImage: string | null;
  }>({
    template: 'dual-title',
    backgroundImage: null,
    mainTitle: '',
    subtitle: '',
    avatarImage: null,
  });
  const [isGeneratingMainTitle, setIsGeneratingMainTitle] = useState(false);
  const [isGeneratingSubTitle, setIsGeneratingSubTitle] = useState(false);
  const [isDesigning, setIsDesigning] = useState(false);
  const [showPointsModal, setShowPointsModal] = useState(false);
  const showRechargeModal = usePointStore(state => state.showRechargeModal);
  const setShowRechargeModal = usePointStore(state => state.setShowRechargeModal);
  const fetchBalance = usePointStore(state => state.fetchBalance);

  // 弹窗状态
  const [bgModalOpen, setBgModalOpen] = useState(false);
  const [avatarModalOpen, setAvatarModalOpen] = useState(false);

  // 背景图配置
  const [modalBgs, setModalBgs] = useState<BgImage[]>([]);
  const [lastModalBgIds, setLastModalBgIds] = useState<Set<string>>(new Set());

  const { canvasRef, initCanvas, renderCover, exportPng } = useCoverFabric();

  const { checkBalance } = usePointsCheck();

  // 智能生成标题
  const handleGenerateTitle = async (titleType: 'main' | 'sub') => {
    const projectStore = useProjectStore.getState();
    const utterances = projectStore.subtitleAlignment?.utterances;
    if (!utterances || utterances.length === 0) {
      toast.error('暂无脚本内容，请先生成脚本');
      return;
    }
    const titlePoints = usePointStore.getState().getRule('title')?.points || 1;
    const canProceed = await checkBalance(titlePoints, '标题生成', true);
    if (!canProceed) {return;}

    const scriptContent = utterances.map(u => u.text).join('\n');
    const maxLength = titleType === 'main' ? 6 : 26;

    if (titleType === 'main') {
      setIsGeneratingMainTitle(true);
    } else {
      setIsGeneratingSubTitle(true);
    }
    try {
      const res = await scriptApi.generateTitle({
        scriptContent,
        titleType,
        maxLength,
        usage: 'cover',
      });
      setConfig((prev) => ({
        ...prev,
        [titleType === 'main' ? 'mainTitle' : 'subtitle']: res.title,
      }));
      toast.success(`${titleType === 'main' ? '主标题' : '副标题'}生成成功`);
    } catch (e) {
      const msg = getFriendlyErrorMessage(e, '标题生成失败，请稍后重试');
      if (msg.includes('积分不足')) {
        setShowPointsModal(true);
        return;
      }
      toast.error(msg);
    } finally {
      if (titleType === 'main') {
        setIsGeneratingMainTitle(false);
      } else {
        setIsGeneratingSubTitle(false);
      }
    }
  };

  // 加载背景图 — 系统图库 + 本地上传
  const localBgRef = useRef<HTMLInputElement | null>(null);
  const blobUrlsRef = useRef<Set<string>>(new Set());
  const [bgList, setBgList] = useState<BgImage[]>([]);

  useEffect(() => {
    const loadBackgrounds = async () => {
      try {
        const backgrounds = await coverApi.getBackgrounds('bk');
        const list: BgImage[] = backgrounds.map((bg: CoverBackground) => ({
          id: String(bg.id),
          src: bg.url,
          name: bg.title || '背景图',
        }));
        setBgList(list);
      } catch (err) {
        console.error('[CoverDesign] 加载背景图失败:', err);
      }
    };
    loadBackgrounds();
  }, []);

  // 本地上传背景图
  const handleLocalBgUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (!file) {return;}

    // 释放旧的 Blob URL
    const oldBg = config.backgroundImage;
    if (oldBg && oldBg.startsWith('blob:')) {
      URL.revokeObjectURL(oldBg);
      blobUrlsRef.current.delete(oldBg);
    }

    const path = (file as FileWithPath).path || (file as FileWithPath).webkitRelativePath || '';
    if (!path) {
      // Tauri 文件选择器通常有 path，如果没有则使用 Object URL
      const url = URL.createObjectURL(file);
      blobUrlsRef.current.add(url);
      setConfig(prev => ({ ...prev, backgroundImage: url }));
    } else {
      setConfig(prev => ({ ...prev, backgroundImage: path }));
    }
    setBgModalOpen(false);
    // 清空 input 以便下次选择同一文件
    e.target.value = '';
  };

  // 弹窗展示 7 张背景图 + 1 个上传入口
  const openBgModal = () => {
    const picked = pickSeven(bgList, lastModalBgIds);
    setModalBgs(picked);
    setLastModalBgIds(new Set(picked.map(b => b.id)));
    setBgModalOpen(true);
  };

  // 弹窗换一组
  const shuffleModalBgs = () => {
    const picked = pickSeven(bgList, lastModalBgIds);
    setModalBgs(picked);
    setLastModalBgIds(new Set(picked.map(b => b.id)));
  };

  // 组件卸载时释放所有 Blob URL
  useEffect(() => {
    const urls = blobUrlsRef.current;
    return () => {
      urls.forEach(url => URL.revokeObjectURL(url));
      urls.clear();
    };
  }, []);

  // 初始化 Canvas
  useEffect(() => {
    initCanvas();
  }, [initCanvas]);

  // 加载之前保存的封面配置
  useEffect(() => {
    if (!coverConfig) {return;}
    setConfig((prev) => ({
      template: coverConfig.template || prev.template,
      backgroundImage: coverConfig.backgroundImage ?? prev.backgroundImage,
      mainTitle: coverConfig.mainTitle ?? coverConfig.caption ?? prev.mainTitle,
      subtitle: coverConfig.subtitle ?? prev.subtitle,
      avatarImage: coverConfig.avatarImage ?? prev.avatarImage,
    }));
  }, [coverConfig]);

  // 背景图/形象变化时自动保存 coverConfig（防抖，只监听视觉素材）
  useEffect(() => {
    if (!projectId) {return;}
    const timer = setTimeout(() => {
      useProjectStore.getState().setCoverConfig({
        template: config.template,
        backgroundImage: config.backgroundImage,
        mainTitle: config.mainTitle,
        subtitle: config.subtitle,
        avatarImage: config.avatarImage,
      });
    }, 300);
    return () => clearTimeout(timer);
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [config.backgroundImage, config.avatarImage, projectId]);

  // 配置变化时重新渲染 Canvas
  useEffect(() => {
    const timer = setTimeout(() => {
      renderCover(config);
    }, 50);
    return () => clearTimeout(timer);
  }, [config, renderCover]);

  // 生成封面图
  const handleGenerate = async () => {
    if (!projectId) {return;}
    if (!config.mainTitle.trim()) {return;}

    const coverPoints = usePointStore.getState().getRule('cover_design')?.points || 2;
    await fetchBalance();
    const currentBalance = usePointStore.getState().balance;
    if (currentBalance < coverPoints) {
      setShowPointsModal(true);
      return;
    }
    setShowPointsModal(false);

    setIsDesigning(true);
    useProgressStore.getState().show('封面设计');

    try {
      useProgressStore.getState().update('正在设计封面...');

      const oldCoverPath = useProjectStore.getState().coverPath;
      if (oldCoverPath) {
        try {
          await invoke<{ code: number; message: string }>('delete_project_file', {
            projectId,
            filePath: oldCoverPath,
          });
        } catch {
          // no-op
        }
      }

      const dataUrl = exportPng();
      if (!dataUrl) {
        throw new Error('封面设计失败');
      }
      const base64 = dataUrl.split(',')[1];

      const result = await invoke<{
        code: number;
        data?: string;
        message: string;
      }>('save_project_asset', {
        projectId,
        filename: `cover_${Date.now()}.png`,
        base64Data: base64,
      });

      if (result.code !== 200 || !result.data) {
        throw new Error(result.message);
      }

      const coverDesignPoints = usePointStore.getState().getRule('cover_design')?.points || 2;
      await pointsApi.consumePoints({
        points: coverDesignPoints,
        sourceType: 'cover_design',
        sourceId: `cover_design_${useAuthStore.getState().user?.id || 'unknown'}_${Date.now()}`,
        description: '封面设计',
      });
      await usePointStore.getState().fetchBalance();

      setCoverPath(result.data);
      setCoverConfig({
        template: config.template,
        backgroundImage: config.backgroundImage,
        mainTitle: config.mainTitle.trim(),
        subtitle: config.subtitle.trim(),
        avatarImage: config.avatarImage,
      });

      useProjectStore.getState().clearStepDirty(5);
      useProjectStore.getState().markStepsDirty(5);
      useProgressStore.getState().success('封面设计完成', coverDesignPoints);
    } catch (error: unknown) {
      const message = (error instanceof Error ? error.message : String(error)) || '封面设计失败';
      console.error('封面设计失败:', error);
      if (message.includes('402') || message.includes('积分不足')) {
        useProgressStore.getState().hide();
        setShowPointsModal(true);
      } else {
        useProgressStore.getState().error(message);
      }
    } finally {
      setIsDesigning(false);
    }
  };

  // 封面形象库
  const { coverAvatars, loadCoverAvatars } = useCoverAvatarStore();
  useEffect(() => {
    loadCoverAvatars();
  }, [loadCoverAvatars]);

  const currentAvatar = coverAvatars.find(a => a.imageUrl === config.avatarImage);
  const canGenerate = !!config.mainTitle.trim();

  return (
    <div className="step-layout cover-design-variant cover-design">
      {isStepDirty && (
        <div className="step-dirty-banner" style={{ gridColumn: '1 / -1', margin: '0 0 var(--spacing-md) 0' }}>
          <span>上游数据已更新，当前封面可能与最新内容不匹配，建议重新设计</span>
        </div>
      )}
      <ConfirmModal
        open={showPointsModal}
        type="warning"
        title="积分不足"
        description="请先充值积分后再进行尝试"
        confirmText="立即充值"
        cancelText="稍后再说"
        confirmButtonType="danger"
        onConfirm={() => {
          setShowPointsModal(false);
          setShowRechargeModal(true);
        }}
        onCancel={() => setShowPointsModal(false)}
        onClose={() => setShowPointsModal(false)}
      />
      <RechargeModal
        open={showRechargeModal}
        onClose={() => setShowRechargeModal(false)}
        onRechargeSuccess={() => {
          fetchBalance();
          setShowPointsModal(false);
        }}
      />

      {/* 背景图弹窗 */}
      <Modal
        open={bgModalOpen}
        onClose={() => setBgModalOpen(false)}
        title="选择背景图片"
        width="560px"
      >
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <div className="modal-bg-grid">
            {/* 第 1 个卡片：本地上传 */}
            <button
              className="modal-bg-thumb modal-bg-upload"
              onClick={() => localBgRef.current?.click()}
              title="使用本地图片作为背景"
            >
              <div className="upload-placeholder">
                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
                  <path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4" />
                  <polyline points="17,8 12,3 7,8" />
                  <line x1="12" y1="3" x2="12" y2="15" />
                </svg>
                <span>本地上传</span>
              </div>
            </button>
            <input
              ref={localBgRef}
              type="file"
              accept="image/*"
              style={{ display: 'none' }}
              onChange={handleLocalBgUpload}
            />
            {modalBgs.map((bg) => (
              <button
                key={bg.id}
                className={`modal-bg-thumb ${config.backgroundImage === bg.src ? 'active' : ''}`}
                onClick={() => {
                  setConfig((prev) => ({ ...prev, backgroundImage: bg.src }));
                  setBgModalOpen(false);
                }}
                title={bg.name}
              >
                <img
                  src={bg.src}
                  alt={bg.name}
                  loading="lazy"
                  onError={(e) => {
                    (e.target as HTMLImageElement).style.display = 'none';
                    const parent = (e.target as HTMLImageElement).parentElement;
                    if (parent) {parent.classList.add('modal-bg-error');}
                  }}
                />
              </button>
            ))}
          </div>
          <div style={{ display: 'flex', gap: 12, justifyContent: 'flex-end' }}>
            <button
              className="btn btn-secondary btn-sm"
              onClick={shuffleModalBgs}
              disabled={bgList.length <= 3}
            >
              换一组
            </button>
            <button className="btn btn-secondary btn-sm" onClick={() => setBgModalOpen(false)}>取消</button>
          </div>
        </div>
      </Modal>

      {/* 封面形象弹窗 */}
      <Modal
        open={avatarModalOpen}
        onClose={() => setAvatarModalOpen(false)}
        title="选择封面形象"
        width="480px"
      >
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          <div className="modal-avatar-grid">
            <button
              className={`modal-avatar-thumb ${config.avatarImage === null ? 'active' : ''}`}
              onClick={() => {
                setConfig((prev) => ({ ...prev, avatarImage: null }));
                setAvatarModalOpen(false);
              }}
            >
              <div className="avatar-placeholder">不使用</div>
            </button>
            {coverAvatars.map((avatar) => (
              <button
                key={avatar.id}
                className={`modal-avatar-thumb ${config.avatarImage === avatar.imageUrl ? 'active' : ''}`}
                onClick={() => {
                  setConfig((prev) => ({ ...prev, avatarImage: avatar.imageUrl }));
                  setAvatarModalOpen(false);
                }}
                title={avatar.name}
              >
                <img
                  src={avatar.imageUrl}
                  alt={avatar.name}
                  loading="lazy"
                  onError={(e) => {
                    (e.target as HTMLImageElement).style.display = 'none';
                    const parent = (e.target as HTMLImageElement).parentElement;
                    if (parent) {parent.classList.add('avatar-thumb-error');}
                  }}
                />
              </button>
            ))}
          </div>
          {coverAvatars.length === 0 && (
            <div style={{ textAlign: 'center', color: 'var(--text-secondary)', fontSize: 'var(--font-xs)', padding: '8px 0' }}>
              暂无封面形象，请在「内容管理 → 封面形象」中上传
            </div>
          )}
          <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
            <button className="btn btn-secondary btn-sm" onClick={() => setAvatarModalOpen(false)}>取消</button>
          </div>
        </div>
      </Modal>

      {/* 左侧：配置区域 */}
      <div className="step-panel-left">
        <div
          className="cover-config-scroll"
          style={{
            flex: 1,
            minHeight: 0,
            overflowY: 'auto',
            display: 'flex',
            flexDirection: 'column',
            gap: 'var(--spacing-lg)',
          }}
        >
          {/* 视觉素材：背景图 + 封面形象 同一行 */}
          <div className="panel-section">
            <label className="panel-label">视觉素材</label>
            <div className="visual-assets-row">
              {/* 背景图卡片 */}
              <button
                className="visual-asset-card"
                onClick={openBgModal}
                title="点击更换背景"
              >
                <div className="visual-asset-image-wrap">
                  <div className="visual-asset-label">背景图片</div>
                  {config.backgroundImage ? (
                    <img
                      src={config.backgroundImage}
                      alt="背景"
                      onError={(e) => {
                        (e.target as HTMLImageElement).style.display = 'none';
                      }}
                    />
                  ) : (
                    <div className="visual-asset-placeholder">
                      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
                        <rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
                        <circle cx="8.5" cy="8.5" r="1.5" />
                        <polyline points="21 15 16 10 5 21" />
                      </svg>
                      <span>选择背景</span>
                    </div>
                  )}
                  <div className="visual-asset-overlay">
                    <span className="visual-asset-overlay-text">
                      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
                        <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
                        <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
                      </svg>
                      更换
                    </span>
                  </div>
                </div>
              </button>

              {/* 封面形象卡片 */}
              <button
                className="visual-asset-card"
                onClick={() => setAvatarModalOpen(true)}
                title="点击更换形象"
              >
                <div className="visual-asset-image-wrap">
                  <div className="visual-asset-label">封面形象</div>
                  {currentAvatar ? (
                    <img
                      src={currentAvatar.imageUrl}
                      alt={currentAvatar.name}
                      onError={(e) => {
                        (e.target as HTMLImageElement).style.display = 'none';
                      }}
                    />
                  ) : (
                    <div className="visual-asset-placeholder">
                      <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
                        <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
                        <circle cx="12" cy="7" r="4" />
                      </svg>
                      <span>选择形象</span>
                    </div>
                  )}
                  <div className="visual-asset-overlay">
                    <span className="visual-asset-overlay-text">
                      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
                        <path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" />
                        <path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" />
                      </svg>
                      更换
                    </span>
                  </div>
                </div>
              </button>
            </div>
          </div>

          {/* 文案配置 */}
          <div className="panel-section">
            <label className="panel-label">文案配置</label>
            <div className="title-input-row">
              <input
                type="text"
                className="input"
                placeholder="输入主标题"
                value={config.mainTitle}
                maxLength={6}
                onChange={(e) =>
                  setConfig((prev) => ({ ...prev, mainTitle: e.target.value }))
                }
              />
              <button
                className="btn btn-ghost title-generate-btn"
                onClick={() => handleGenerateTitle('main')}
                disabled={isGeneratingMainTitle}
                title="根据脚本内容智能生成主标题"
              >
                {isGeneratingMainTitle ? '生成中...' : '智能生成'}
              </button>
            </div>
            <div className="title-input-row" style={{ marginTop: 8 }}>
              <textarea
                className="input subtitle-textarea"
                placeholder="输入副标题"
                value={config.subtitle}
                maxLength={52}
                rows={2}
                onChange={(e) =>
                  setConfig((prev) => ({ ...prev, subtitle: e.target.value }))
                }
              />
              <button
                className="btn btn-ghost title-generate-btn"
                onClick={() => handleGenerateTitle('sub')}
                disabled={isGeneratingSubTitle}
                title="根据脚本内容智能生成副标题"
              >
                {isGeneratingSubTitle ? '生成中...' : '智能生成'}
              </button>
            </div>
          </div>
        </div>

        {/* 操作按钮 */}
        <div style={{ display: 'flex', gap: 12, marginTop: 'auto', flexShrink: 0 }}>
          <button
            className="btn btn-primary"
            disabled={isDesigning || !canGenerate}
            onClick={handleGenerate}
            style={{ flex: 1 }}
          >
            {isDesigning
              ? '生成中...'
              : coverPath
                ? `重新生成(${usePointStore.getState().getRule('cover_design')?.points || 2}积分)`
                : `生成封面(${usePointStore.getState().getRule('cover_design')?.points || 2}积分)`}
          </button>
          {coverPath && (
            <button
              className="btn btn-secondary"
              onClick={async () => {
                try {
                  const filename = coverPath.split(/[\\/]/).pop() || 'cover.png';
                  const targetPath = await save({
                    defaultPath: filename,
                    filters: [{ name: '图片', extensions: ['png'] }],
                  });
                  if (!targetPath) {return;}
                  const res = await invoke<{ code: number; data?: string; message: string }>('export_product', {
                    sourcePath: coverPath,
                    targetPath,
                  });
                  if (res.code === 200) {
                    toast.success('封面导出成功');
                  } else {
                    toast.error(res.message || '导出失败');
                  }
                } catch {
                  toast.error('导出失败');
                }
              }}
              style={{ flex: 1 }}
            >
              导出封面
            </button>
          )}
        </div>
      </div>

      {/* 右侧：竖屏预览 */}
      <div className="step-panel-right video-gen-right">
        <div className="video-preview-area">
          <div className="video-preview-header">封面预览</div>
          <div className="video-preview-wrapper">
            <div className="video-preview-container">
              <canvas
                ref={canvasRef}
                style={{
                  width: '337px',
                  height: '600px',
                  display: 'block',
                }}
              />
              {!config.backgroundImage && (
                <div className="cover-preview-placeholder">
                  <svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
                    <rect x="3" y="3" width="18" height="18" rx="2" ry="2" />
                    <circle cx="8.5" cy="8.5" r="1.5" />
                    <polyline points="21 15 16 10 5 21" />
                  </svg>
                  <span>请先选择背景图片</span>
                </div>
              )}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}
