/**
 * 我的音色页面 — V21 设计系统（任务 3.12 升级 / 3.15 进度轮询）
 *
 * 功能：克隆音色卡片列表、试听播放、状态标签、删除、编辑名称、空状态引导
 * 使用 useCloneProgress hook 实现 processing 状态自动轮询
 */
import React, { useState, useCallback, useRef } from "react";
import { useNavigate } from "react-router-dom";
import {
  PlayCircleOutlined,
  PauseCircleOutlined,
  DeleteOutlined,
  EditOutlined,
  PlusOutlined,
  SoundOutlined,
  ClockCircleOutlined,
} from "@ant-design/icons";
import { Button, Modal, Input, Tooltip } from "@/components/ui";
import type { ButtonProps } from "antd";
import PageHead from "@/components/layout/PageHead";
import { useCloneProgress } from "@/hooks/useCloneProgress";
import {
  deleteVoiceClone,
  updateVoiceClone,
  formatDuration,
} from "@/api/voiceClone";
import type { VoiceClone, VoiceCloneStatus } from "@/api/voiceClone";
import "./my-voices.css";

/* ============================================================
 * 工具函数
 * ============================================================ */
function formatDate(isoStr: string): string {
  const d = new Date(isoStr);
  return d.toLocaleDateString("zh-CN", {
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
  });
}

/* ============================================================
 * 状态配置
 * ============================================================ */
const STATUS_CONFIG: Record<
  VoiceCloneStatus,
  { label: string; dotClass: string }
> = {
  ready: { label: "就绪", dotClass: "xx-mv-status-dot--ready" },
  processing: { label: "克隆中", dotClass: "xx-mv-status-dot--processing" },
  failed: { label: "失败", dotClass: "xx-mv-status-dot--failed" },
};

/* ============================================================
 * Toast 组件
 * ============================================================ */
interface ToastItem {
  id: number;
  message: string;
  type: "success" | "error";
}
let _toastId = 0;

/* ============================================================
 * 音色卡片组件
 * ============================================================ */
interface VoiceCardProps {
  voice: VoiceClone;
  isPlaying: boolean;
  onTogglePlay: (voice: VoiceClone) => void;
  onEdit: (voice: VoiceClone) => void;
  onDelete: (voice: VoiceClone) => void;
}

const VoiceCard: React.FC<VoiceCardProps> = ({
  voice,
  isPlaying,
  onTogglePlay,
  onEdit,
  onDelete,
}) => {
  const statusCfg = STATUS_CONFIG[voice.status];
  const isReady = voice.status === "ready";

  return (
    <div className={`xx-mv-card xx-mv-card--${voice.status}`}>
      {/* 头部：头像 + 名称 + 状态 */}
      <div className="xx-mv-card-header">
        <div className={`xx-mv-card-avatar xx-mv-card-avatar--${voice.status}`}>
          <SoundOutlined />
        </div>
        <div className="xx-mv-card-info">
          <h4 className="xx-mv-card-name">{voice.name}</h4>
          <span className="xx-mv-status">
            <span className={`xx-mv-status-dot ${statusCfg.dotClass}`} />
            {statusCfg.label}
          </span>
        </div>
      </div>

      {/* 元信息 */}
      <div className="xx-mv-card-meta">
        <span className="xx-mv-card-meta-item">
          <ClockCircleOutlined /> {formatDate(voice.created_at)}
        </span>
        {voice.duration_seconds > 0 && (
          <span className="xx-mv-card-meta-item">
            {formatDuration(voice.duration_seconds)}
          </span>
        )}
      </div>

      {/* 进度条（克隆中 — indeterminate 条纹流动动画） */}
      {voice.status === "processing" && (
        <div className="xx-mv-progress xx-mv-progress--indeterminate">
          <div className="xx-mv-progress-bar" />
          <span className="xx-mv-progress-text">处理中…</span>
        </div>
      )}

      {/* 操作区 */}
      <div className="xx-mv-card-actions">
        {isReady ? (
          <Button
            buttonType={isPlaying ? "secondary" : "ghost"}
            buttonSize="sm"
            onClick={() => onTogglePlay(voice)}
          >
            {isPlaying ? (
              <>
                <PauseCircleOutlined /> 暂停
              </>
            ) : (
              <>
                <PlayCircleOutlined /> 试听
              </>
            )}
          </Button>
        ) : voice.status === "failed" ? (
          <Button buttonType="ghost" buttonSize="sm" disabled>
            克隆失败
          </Button>
        ) : (
          <Button buttonType="ghost" buttonSize="sm" disabled>
            处理中...
          </Button>
        )}
        <div className="xx-mv-card-icon-actions">
          <Tooltip title="编辑名称">
            <button
              type="button"
              className="xx-mv-icon-btn"
              onClick={() => onEdit(voice)}
              disabled={!isReady}
            >
              <EditOutlined />
            </button>
          </Tooltip>
          <Tooltip title="删除">
            <button
              type="button"
              className="xx-mv-icon-btn xx-mv-icon-btn--danger"
              onClick={() => onDelete(voice)}
            >
              <DeleteOutlined />
            </button>
          </Tooltip>
        </div>
      </div>
    </div>
  );
};

/* ============================================================
 * 主页面组件
 * ============================================================ */
const MyVoices: React.FC = () => {
  const navigate = useNavigate();
  const { clones, loading, removeClone, updateClone, hasProcessing } =
    useCloneProgress();
  const [playingId, setPlayingId] = useState<string | null>(null);
  const [toasts, setToasts] = useState<ToastItem[]>([]);
  const [editModalOpen, setEditModalOpen] = useState(false);
  const [editingVoice, setEditingVoice] = useState<VoiceClone | null>(null);
  const [editName, setEditName] = useState("");
  const [deleteConfirmId, setDeleteConfirmId] = useState<string | null>(null);
  const audioRef = useRef<HTMLAudioElement | null>(null);

  // Toast
  const showToast = useCallback((message: string, type: ToastItem["type"]) => {
    const id = ++_toastId;
    setToasts((prev) => [...prev, { id, message, type }]);
    setTimeout(
      () => setToasts((prev) => prev.filter((t) => t.id !== id)),
      3000,
    );
  }, []);

  // 试听播放
  const handleTogglePlay = useCallback(
    (voice: VoiceClone) => {
      if (playingId === voice.id) {
        audioRef.current?.pause();
        setPlayingId(null);
        return;
      }
      if (audioRef.current) {
        audioRef.current.pause();
      }
      if (!voice.sample_url) {
        showToast("暂无试听音频", "error");
        return;
      }
      const audio = new Audio(voice.sample_url);
      audioRef.current = audio;
      audio.play().catch(() => showToast("播放失败，请检查音频文件", "error"));
      audio.onended = () => setPlayingId(null);
      setPlayingId(voice.id);
    },
    [playingId, showToast],
  );

  // 编辑
  const handleEdit = (voice: VoiceClone) => {
    setEditingVoice(voice);
    setEditName(voice.name);
    setEditModalOpen(true);
  };

  const handleEditConfirm = async () => {
    if (!editingVoice || !editName.trim()) return;
    try {
      const updated = await updateVoiceClone(editingVoice.id, {
        name: editName.trim(),
      });
      updateClone(updated);
      setEditModalOpen(false);
      setEditingVoice(null);
      showToast("名称已更新", "success");
    } catch {
      showToast("更新失败，请重试", "error");
    }
  };

  // 删除
  const handleDelete = (voice: VoiceClone) => {
    setDeleteConfirmId(voice.id);
  };

  const handleDeleteConfirm = async () => {
    if (!deleteConfirmId) return;
    try {
      await deleteVoiceClone(deleteConfirmId);
      removeClone(deleteConfirmId);
      setDeleteConfirmId(null);
      showToast("音色已删除", "success");
    } catch {
      showToast("删除失败，请重试", "error");
    }
  };

  // 克隆新音色
  const handleCloneNew = () => {
    navigate("/app/voices");
  };

  // 统计
  const readyCount = clones.filter((v) => v.status === "ready").length;
  const processingCount = clones.filter(
    (v) => v.status === "processing",
  ).length;

  return (
    <div className="xx-mv-page">
      <PageHead
        title="我的音色"
        description="管理你的克隆音色，试听并使用在视频配音中"
        breadcrumb={[
          { label: "配音中心", path: "/app/voices" },
          { label: "我的音色" },
        ]}
        actions={
          <Button buttonType="primary" onClick={handleCloneNew}>
            <PlusOutlined /> 克隆新音色
          </Button>
        }
      />

      {/* 轮询提示 */}
      {hasProcessing && (
        <div className="xx-mv-polling-hint">
          <span className="xx-mv-polling-dot" />
          正在同步克隆进度...
        </div>
      )}

      {/* 统计栏 */}
      {!loading && clones.length > 0 && (
        <div className="xx-mv-stats">
          <span className="xx-mv-stat">
            共 <strong>{clones.length}</strong> 个音色
          </span>
          <span className="xx-mv-stat xx-mv-stat--ready">
            <span className="xx-mv-stat-dot xx-mv-stat-dot--ready" />
            就绪 {readyCount}
          </span>
          {processingCount > 0 && (
            <span className="xx-mv-stat xx-mv-stat--processing">
              <span className="xx-mv-stat-dot xx-mv-stat-dot--processing" />
              克隆中 {processingCount}
            </span>
          )}
        </div>
      )}

      {/* 加载状态 */}
      {loading && (
        <div className="xx-mv-empty">
          <div className="xx-mv-empty-icon">⏳</div>
          <p className="xx-mv-empty-desc">加载中...</p>
        </div>
      )}

      {/* 卡片网格 */}
      {!loading && clones.length > 0 && (
        <div className="xx-mv-grid">
          {clones.map((voice) => (
            <VoiceCard
              key={voice.id}
              voice={voice}
              isPlaying={playingId === voice.id}
              onTogglePlay={handleTogglePlay}
              onEdit={handleEdit}
              onDelete={handleDelete}
            />
          ))}
        </div>
      )}

      {/* 空状态 */}
      {!loading && clones.length === 0 && (
        <div className="xx-mv-empty">
          <div className="xx-mv-empty-icon">🎤</div>
          <h3 className="xx-mv-empty-title">还没有克隆音色</h3>
          <p className="xx-mv-empty-desc">
            上传你的声音样本，AI 将克隆生成你的专属音色
          </p>
          <Button buttonType="primary" onClick={handleCloneNew}>
            <PlusOutlined /> 去配音库克隆
          </Button>
        </div>
      )}

      {/* 编辑弹窗 */}
      <Modal
        open={editModalOpen}
        title="编辑音色名称"
        onCancel={() => setEditModalOpen(false)}
        onOk={handleEditConfirm}
        okText="保存"
        cancelText="取消"
      >
        <Input
          value={editName}
          onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
            setEditName(e.target.value)
          }
          placeholder="输入音色名称"
          autoFocus
          onKeyDown={(e: React.KeyboardEvent) => {
            if (e.key === "Enter") handleEditConfirm();
          }}
        />
      </Modal>

      {/* 删除确认弹窗 */}
      <Modal
        open={!!deleteConfirmId}
        title="确认删除"
        onCancel={() => setDeleteConfirmId(null)}
        onOk={handleDeleteConfirm}
        okText="删除"
        cancelText="取消"
        okButtonProps={{ danger: true } as ButtonProps}
      >
        <p>确定要删除这个克隆音色吗？删除后无法恢复。</p>
      </Modal>

      {/* Toast */}
      {toasts.length > 0 && (
        <div className="xx-mv-toast-container">
          {toasts.map((t) => (
            <div key={t.id} className={`xx-mv-toast xx-mv-toast--${t.type}`}>
              {t.type === "success" ? "✅" : "❌"} {t.message}
            </div>
          ))}
        </div>
      )}
    </div>
  );
};

export default MyVoices;
