/**
 * CloneModal — 音色克隆弹窗（共享组件）
 *
 * 功能：
 * - 步骤引导：上传/录制音频 → 填写信息 → 提交克隆
 * - 两种输入方式：上传文件（wav/mp3/m4a，≤10MB）或浏览器原生录音（MediaRecorder）
 * - 提交：先 uploadAsset 获取真实 URL，再 createVoiceClone
 * - 进度展示：上传中 → 克隆中 → 完成（三阶段可视化）
 * - 错误处理：上传失败、格式错误、大小超限、录音权限拒绝等提示
 *
 * V21 Design System — 零 antd 直接导入
 */
import React, { useState, useCallback, useRef, useEffect } from "react";
import { Modal, Button } from "@/components/ui";
import { createVoiceClone, toVoiceClone } from "@/api/voiceClone";
import type { VoiceClone } from "@/api/voiceClone";
import { uploadAsset } from "@/api/assets";
import "./clone-modal.css";

/* ── 类型定义 ───────────────────────────────────────────── */

type ModalPhase = "input" | "uploading" | "cloning" | "done";

export interface CloneModalProps {
  /** 弹窗是否可见 */
  open: boolean;
  /** 关闭弹窗回调 */
  onClose: () => void;
  /** 克隆成功回调（返回新创建的音色） */
  onSuccess?: (voice: VoiceClone) => void;
}

/* ── 进度阶段配置 ─────────────────────────────────────────── */

const PROGRESS_STEPS: { key: string; label: string; icon: string }[] = [
  { key: "uploading", label: "上传中", icon: "📤" },
  { key: "cloning", label: "克隆中", icon: "🧬" },
  { key: "done", label: "完成", icon: "✅" },
];

/* ── 常量 ───────────────────────────────────────────────── */

const ACCEPTED_EXTENSIONS = ["mp3", "wav", "m4a"];
const ACCEPTED_MIME = ".mp3,.wav,.m4a,audio/mpeg,audio/wav,audio/mp4";
const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB

/** 最长录制时长：5 分钟（秒） */
const MAX_RECORD_SECONDS = 5 * 60;

/* ── 组件 ───────────────────────────────────────────────── */

const CloneModal: React.FC<CloneModalProps> = ({
  open,
  onClose,
  onSuccess,
}) => {
  const [phase, setPhase] = useState<ModalPhase>("input");
  const [voiceName, setVoiceName] = useState("");
  const [voiceDescription, setVoiceDescription] = useState("");
  const [selectedFile, setSelectedFile] = useState<File | null>(null);
  const [dragActive, setDragActive] = useState(false);
  const [errorMessage, setErrorMessage] = useState("");

  // 录音状态
  const [isRecording, setIsRecording] = useState(false);
  const [recordTime, setRecordTime] = useState(0);
  const [recordedBlob, setRecordedBlob] = useState<Blob | null>(null);

  const fileInputRef = useRef<HTMLInputElement>(null);
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const recordTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const mediaRecorderRef = useRef<MediaRecorder | null>(null);
  const audioChunksRef = useRef<Blob[]>([]);
  /** 默认音色名称计数器（组件级 ref，避免多实例串号） */
  const cloneCounterRef = useRef(1);

  /** 生成下一个默认音色名称 */
  const getNextDefaultName = useCallback((): string => {
    const name = `我的声音 ${cloneCounterRef.current}`;
    cloneCounterRef.current += 1;
    return name;
  }, []);

  /** 组件卸载时清理定时器和 MediaRecorder */
  useEffect(() => {
    return () => {
      if (timerRef.current) clearTimeout(timerRef.current);
      if (recordTimerRef.current) clearInterval(recordTimerRef.current);
      if (
        mediaRecorderRef.current &&
        mediaRecorderRef.current.state !== "inactive"
      ) {
        mediaRecorderRef.current.stop();
      }
    };
  }, []);

  /** 重置弹窗状态 */
  const resetState = useCallback(() => {
    setPhase("input");
    setVoiceName(getNextDefaultName());
    setVoiceDescription("");
    setSelectedFile(null);
    setDragActive(false);
    setErrorMessage("");
    setIsRecording(false);
    setRecordTime(0);
    setRecordedBlob(null);
    audioChunksRef.current = [];
    if (recordTimerRef.current) {
      clearInterval(recordTimerRef.current);
      recordTimerRef.current = null;
    }
    if (
      mediaRecorderRef.current &&
      mediaRecorderRef.current.state !== "inactive"
    ) {
      mediaRecorderRef.current.stop();
    }
    mediaRecorderRef.current = null;
  }, [getNextDefaultName]);

  /** 关闭弹窗 */
  const handleClose = useCallback(() => {
    resetState();
    onClose();
  }, [resetState, onClose]);

  /** 弹窗打开时重置状态 */
  useEffect(() => {
    if (open) {
      resetState();
    }
  }, [open, resetState]);

  /* ── 文件验证 ──────────────────────────────────────── */

  const validateFile = (file: File): string | null => {
    const ext = file.name.split(".").pop()?.toLowerCase();
    if (!ext || !ACCEPTED_EXTENSIONS.includes(ext)) {
      return "不支持的音频格式，请上传 MP3、WAV 或 M4A 文件";
    }
    if (file.size > MAX_FILE_SIZE) {
      return "文件大小超过 10MB，请压缩后重试";
    }
    return null;
  };

  /* ── 文件上传 ──────────────────────────────────────── */

  const handleUploadClick = () => {
    fileInputRef.current?.click();
  };

  const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0];
    if (file) {
      const error = validateFile(file);
      if (error) {
        setErrorMessage(error);
        setSelectedFile(null);
      } else {
        setErrorMessage("");
        setSelectedFile(file);
        // 清除录音
        setRecordedBlob(null);
        setIsRecording(false);
        setRecordTime(0);
      }
    }
    e.target.value = "";
  };

  /* ── 拖拽 ──────────────────────────────────────────── */

  const handleDrag = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    if (e.type === "dragenter" || e.type === "dragover") {
      setDragActive(true);
    } else if (e.type === "dragleave") {
      setDragActive(false);
    }
  };

  const handleDrop = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setDragActive(false);
    const file = e.dataTransfer.files?.[0];
    if (file) {
      const error = validateFile(file);
      if (error) {
        setErrorMessage(error);
        setSelectedFile(null);
      } else {
        setErrorMessage("");
        setSelectedFile(file);
        setRecordedBlob(null);
        setIsRecording(false);
        setRecordTime(0);
      }
    }
  };

  /* ── 录音（真实 MediaRecorder） ───────────────────── */

  const handleRecord = async () => {
    if (isRecording) {
      // 停止录制
      setIsRecording(false);
      if (recordTimerRef.current) {
        clearInterval(recordTimerRef.current);
        recordTimerRef.current = null;
      }
      if (
        mediaRecorderRef.current &&
        mediaRecorderRef.current.state !== "inactive"
      ) {
        mediaRecorderRef.current.stop();
      }
    } else {
      // 开始录制
      try {
        const stream = await navigator.mediaDevices.getUserMedia({
          audio: true,
        });
        const mediaRecorder = new MediaRecorder(stream);
        mediaRecorderRef.current = mediaRecorder;
        audioChunksRef.current = [];

        mediaRecorder.ondataavailable = (event) => {
          if (event.data.size > 0) {
            audioChunksRef.current.push(event.data);
          }
        };

        mediaRecorder.onstop = () => {
          const blob = new Blob(audioChunksRef.current, { type: "audio/webm" });
          setRecordedBlob(blob);
          // 清除上传的文件
          setSelectedFile(null);
          // 停止音轨
          stream.getTracks().forEach((track) => track.stop());
        };

        mediaRecorder.start();
        setIsRecording(true);
        setRecordTime(0);
        setRecordedBlob(null);
        setErrorMessage("");

        recordTimerRef.current = setInterval(() => {
          setRecordTime((prev) => {
            const next = prev + 1;
            if (next >= MAX_RECORD_SECONDS) {
              // 达到 5 分钟上限，自动停止录制
              setTimeout(() => {
                setIsRecording(false);
                if (recordTimerRef.current) {
                  clearInterval(recordTimerRef.current);
                  recordTimerRef.current = null;
                }
                if (
                  mediaRecorderRef.current &&
                  mediaRecorderRef.current.state !== "inactive"
                ) {
                  mediaRecorderRef.current.stop();
                }
                setErrorMessage("已达最长录制时长（5分钟），已自动停止");
              }, 0);
              return MAX_RECORD_SECONDS;
            }
            return next;
          });
        }, 1000);
      } catch {
        setErrorMessage("无法访问麦克风，请检查浏览器权限设置");
      }
    }
  };

  /** 格式化录制时间 mm:ss */
  const formatRecordTime = (seconds: number): string => {
    const m = Math.floor(seconds / 60);
    const s = seconds % 60;
    return `${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
  };

  /* ── 表单验证 ──────────────────────────────────────── */

  const hasAudio = selectedFile !== null || recordedBlob !== null;

  const validateForm = (): string | null => {
    const name = voiceName.trim();
    if (!name) {
      return "请输入音色名称";
    }
    if (name.length < 2 || name.length > 20) {
      return "音色名称需在 2-20 个字符之间";
    }
    if (!hasAudio) {
      return "请上传音频文件或录制一段声音";
    }
    return null;
  };

  /* ── 提交克隆 ──────────────────────────────────────── */

  const handleSubmit = async () => {
    const formError = validateForm();
    if (formError) {
      setErrorMessage(formError);
      return;
    }

    setErrorMessage("");

    try {
      // 阶段 1：上传音频
      setPhase("uploading");

      let fileToUpload: File;
      if (selectedFile) {
        fileToUpload = selectedFile;
      } else {
        // 将录音 Blob 转为 File
        fileToUpload = new File(
          [recordedBlob!],
          `recorded-${Date.now()}.webm`,
          {
            type: "audio/webm",
          },
        );
      }

      const formData = new FormData();
      formData.append("file", fileToUpload);
      const uploadResult = await uploadAsset(formData);

      // 阶段 2：克隆
      setPhase("cloning");
      const result = await createVoiceClone({
        name: voiceName.trim(),
        description: voiceDescription.trim() || undefined,
        audio_url: uploadResult.url,
      });

      // 阶段 3：完成
      setPhase("done");

      // 2秒后自动关闭
      timerRef.current = setTimeout(() => {
        onSuccess?.(toVoiceClone(result));
        handleClose();
      }, 2000);
    } catch (err) {
      setPhase("input");
      setErrorMessage(err instanceof Error ? err.message : "克隆失败，请重试");
    }
  };

  /* ── 计算属性 ──────────────────────────────────────── */

  const canSubmit =
    voiceName.trim().length >= 2 && voiceName.trim().length <= 20 && hasAudio;

  const isProcessing = phase === "uploading" || phase === "cloning";

  /** 当前进度索引 */
  const getProgressIndex = (): number => {
    switch (phase) {
      case "uploading":
        return 0;
      case "cloning":
        return 1;
      case "done":
        return 2;
      default:
        return -1;
    }
  };

  const progressIndex = getProgressIndex();

  return (
    <Modal
      open={open}
      onCancel={handleClose}
      title="克隆我的音色"
      width={560}
      footer={null}
      destroyOnClose
      maskClosable={!isProcessing}
      keyboard={!isProcessing}
    >
      {/* ── 输入阶段 ──────────────────────────────────── */}
      {phase === "input" && (
        <div className="xx-clonemodal-body">
          {/* 步骤引导 */}
          <div className="xx-clonemodal-steps">
            <div className="xx-clonemodal-step xx-clonemodal-step--active">
              <div className="xx-clonemodal-step-number">1</div>
              <span className="xx-clonemodal-step-label">上传/录制音频</span>
            </div>
            <div className="xx-clonemodal-step-connector" />
            <div className="xx-clonemodal-step">
              <div className="xx-clonemodal-step-number">2</div>
              <span className="xx-clonemodal-step-label">填写信息</span>
            </div>
            <div className="xx-clonemodal-step-connector" />
            <div className="xx-clonemodal-step">
              <div className="xx-clonemodal-step-number">3</div>
              <span className="xx-clonemodal-step-label">提交克隆</span>
            </div>
          </div>

          {/* 音色名称 */}
          <div className="xx-clonemodal-field">
            <label className="xx-clonemodal-label">
              音色名称 <span className="xx-clonemodal-required">*</span>
            </label>
            <input
              type="text"
              className="xx-clonemodal-input"
              value={voiceName}
              onChange={(e) => setVoiceName(e.target.value)}
              placeholder="输入音色名称（2-20字符）"
              maxLength={20}
            />
            <div className="xx-clonemodal-char-count">
              {voiceName.length}/20
            </div>
          </div>

          {/* 上传区域 */}
          <div className="xx-clonemodal-field">
            <label className="xx-clonemodal-label">上传音频</label>
            <div
              className={`xx-clonemodal-upload-zone${dragActive ? " xx-clonemodal-upload-zone--active" : ""}${selectedFile ? " xx-clonemodal-upload-zone--has-file" : ""}`}
              onClick={handleUploadClick}
              onDragEnter={handleDrag}
              onDragOver={handleDrag}
              onDragLeave={handleDrag}
              onDrop={handleDrop}
            >
              <div className="xx-clonemodal-upload-icon">
                {selectedFile ? "📄" : "🎵"}
              </div>
              <p className="xx-clonemodal-upload-title">
                {selectedFile
                  ? selectedFile.name
                  : "拖拽音频文件到此处，或点击上传"}
              </p>
              <p className="xx-clonemodal-upload-hint">
                支持 MP3、WAV、M4A 格式，最大 10MB
              </p>
              <input
                ref={fileInputRef}
                type="file"
                accept={ACCEPTED_MIME}
                style={{ display: "none" }}
                onChange={handleFileChange}
              />
            </div>
          </div>

          {/* 或分隔 */}
          <div className="xx-clonemodal-divider">
            <div className="xx-clonemodal-divider-line" />
            <span className="xx-clonemodal-divider-text">或</span>
            <div className="xx-clonemodal-divider-line" />
          </div>

          {/* 录制区域 */}
          <div className="xx-clonemodal-field">
            <label className="xx-clonemodal-label">直接录制</label>
            <div className="xx-clonemodal-record-area">
              <div className="xx-clonemodal-record-info">
                <p className="xx-clonemodal-record-hint">
                  {isRecording
                    ? `录制中 ${formatRecordTime(recordTime)}`
                    : recordedBlob
                      ? `已录制 ${formatRecordTime(recordTime)}`
                      : "点击按钮开始录制（最长 5 分钟）"}
                </p>
                {isRecording && (
                  <div className="xx-clonemodal-record-wave">
                    <span className="xx-clonemodal-record-wave-bar" />
                    <span className="xx-clonemodal-record-wave-bar" />
                    <span className="xx-clonemodal-record-wave-bar" />
                    <span className="xx-clonemodal-record-wave-bar" />
                    <span className="xx-clonemodal-record-wave-bar" />
                  </div>
                )}
              </div>
              <button
                type="button"
                className={`xx-clonemodal-record-btn${isRecording ? " xx-clonemodal-record-btn--recording" : ""}`}
                onClick={handleRecord}
                title={isRecording ? "停止录制" : "开始录制"}
              >
                {isRecording ? "⏹" : "🎙️"}
              </button>
            </div>
          </div>

          {/* 音色描述 */}
          <div className="xx-clonemodal-field">
            <label className="xx-clonemodal-label">音色描述</label>
            <textarea
              className="xx-clonemodal-textarea"
              value={voiceDescription}
              onChange={(e) => setVoiceDescription(e.target.value)}
              placeholder="可选，描述这个音色的特点（最多100字符）"
              maxLength={100}
              rows={3}
            />
            <div className="xx-clonemodal-char-count">
              {voiceDescription.length}/100
            </div>
          </div>

          {/* 错误提示 */}
          {errorMessage && (
            <div className="xx-clonemodal-error">
              <span className="xx-clonemodal-error-icon">⚠️</span>
              <span>{errorMessage}</span>
            </div>
          )}

          {/* 提示 */}
          <div className="xx-clonemodal-tip">
            <span className="xx-clonemodal-tip-icon">💡</span>
            <span>
              建议上传 10 秒 ~ 3 分钟的清晰语音，环境安静、语速均匀效果最佳
            </span>
          </div>

          {/* 底部按钮 */}
          <div className="xx-clonemodal-footer">
            <Button buttonType="ghost" onClick={handleClose}>
              取消
            </Button>
            <Button
              buttonType="primary"
              disabled={!canSubmit}
              onClick={handleSubmit}
            >
              🎤 开始克隆
            </Button>
          </div>
        </div>
      )}

      {/* ── 进度阶段（上传中 / 克隆中） ──────────────── */}
      {isProcessing && (
        <div className="xx-clonemodal-progress-body">
          {/* 步骤指示器 */}
          <div className="xx-clonemodal-steps-progress">
            {PROGRESS_STEPS.map((step, idx) => {
              const isActive = idx === progressIndex;
              const isDone = idx < progressIndex;
              const stepClass = [
                "xx-clonemodal-step-progress",
                isActive ? "xx-clonemodal-step-progress--active" : "",
                isDone ? "xx-clonemodal-step-progress--done" : "",
              ]
                .filter(Boolean)
                .join(" ");

              return (
                <React.Fragment key={step.key}>
                  {idx > 0 && (
                    <div
                      className={`xx-clonemodal-step-connector${isDone ? " xx-clonemodal-step-connector--done" : ""}`}
                    />
                  )}
                  <div className={stepClass}>
                    <div className="xx-clonemodal-step-icon">
                      {isDone ? "✓" : step.icon}
                    </div>
                    <span className="xx-clonemodal-step-label">
                      {step.label}
                    </span>
                  </div>
                </React.Fragment>
              );
            })}
          </div>

          {/* 当前阶段描述 */}
          <div className="xx-clonemodal-progress-info">
            {phase === "uploading" && (
              <>
                <div className="xx-clonemodal-progress-spinner" />
                <p className="xx-clonemodal-progress-text">正在上传音频文件…</p>
                <p className="xx-clonemodal-progress-sub">
                  请稍候，正在将音频上传至服务器
                </p>
              </>
            )}
            {phase === "cloning" && (
              <>
                <div className="xx-clonemodal-progress-spinner xx-clonemodal-progress-spinner--cloning" />
                <p className="xx-clonemodal-progress-text">
                  AI 正在克隆你的声音…
                </p>
                <p className="xx-clonemodal-progress-sub">
                  正在分析声音特征，生成专属音色模型
                </p>
              </>
            )}
          </div>
        </div>
      )}

      {/* ── 完成阶段 ──────────────────────────────────── */}
      {phase === "done" && (
        <div className="xx-clonemodal-progress-body">
          {/* 步骤指示器（全部完成） */}
          <div className="xx-clonemodal-steps-progress">
            {PROGRESS_STEPS.map((step, idx) => (
              <React.Fragment key={step.key}>
                {idx > 0 && (
                  <div className="xx-clonemodal-step-connector xx-clonemodal-step-connector--done" />
                )}
                <div className="xx-clonemodal-step-progress xx-clonemodal-step-progress--done">
                  <div className="xx-clonemodal-step-icon">✓</div>
                  <span className="xx-clonemodal-step-label">{step.label}</span>
                </div>
              </React.Fragment>
            ))}
          </div>

          <div className="xx-clonemodal-success">
            <div className="xx-clonemodal-success-icon">🎉</div>
            <h3 className="xx-clonemodal-success-title">克隆已提交</h3>
            <p className="xx-clonemodal-success-desc">
              音色正在生成中，完成后将出现在「我的克隆」列表中
            </p>
          </div>
        </div>
      )}
    </Modal>
  );
};

export default CloneModal;
