/**
 * 素材库页面 — V21 设计系统
 * 两栏布局：左侧素材库列表（260px）+ 右侧素材网格
 * 使用 useQuery 对接后端真实 API（api/assets.ts）
 */
import React, { useMemo, useState } from "react";
import { Upload, Modal as AntModal, message, Popconfirm } from "antd";
import {
  PlusOutlined,
  SearchOutlined,
  InboxOutlined,
  VideoCameraOutlined,
  PictureOutlined,
  PlayCircleOutlined,
  CheckOutlined,
  DeleteOutlined,
  ExperimentOutlined,
  LoadingOutlined,
  ExclamationCircleOutlined,
} from "@ant-design/icons";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import {
  getAssetLibraries,
  createAssetLibrary,
  deleteAssetLibrary,
  getAssets,
  deleteAsset,
  uploadAssetDirect,
  getAssetDiagnosis,
  type AssetLibraryItem,
  type AssetItem as ApiAssetItem,
} from "@/api/assets";
import { Button, Input, Select } from "@/components/ui";
import "./assets.css";

/* ============================================================
 * 类型
 * ============================================================ */
type AssetKind = "video" | "image";
type StatusType = "ok" | "warn" | "bad" | "info";

interface LibraryItem {
  id: string;
  name: string;
  kind: AssetKind;
  count: number;
}

interface AssetItem {
  id: string;
  name: string;
  kind: AssetKind;
  thumbUrl?: string;
  fileUrl?: string;
  status: StatusType;
  statusLabel: string;
  duration?: string;
  size: number;
  createdAt: string;
}

/* ============================================================
 * 映射：后端 → 前端
 * ============================================================ */

/** 根据 mime_type 推断前端 AssetKind */
const inferKind = (mimeType: string): AssetKind => {
  if (mimeType.startsWith("video/")) return "video";
  return "image";
};

/** 根据 quality_score 推断前端状态 */
const inferStatus = (
  score?: number,
  classificationStatus?: string,
): { status: StatusType; label: string } => {
  if (
    classificationStatus === "processing" ||
    classificationStatus === "pending"
  ) {
    return { status: "info", label: "处理中" };
  }
  if (score == null) return { status: "info", label: "待诊断" };
  if (score >= 70) return { status: "ok", label: "合格" };
  if (score >= 40) return { status: "warn", label: "待优化" };
  return { status: "bad", label: "不合格" };
};

/** 格式化时长（秒 → mm:ss） */
const formatDuration = (seconds: number): string => {
  const m = Math.floor(seconds / 60);
  const s = Math.floor(seconds % 60);
  return `${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
};

/** 将后端 AssetLibraryItem 映射为前端 LibraryItem */
const mapLibrary = (item: AssetLibraryItem): LibraryItem => ({
  id: item.id,
  name: item.name,
  kind: (item.kind === "voice" ? "video" : item.kind) || inferKind("video"),
  count: item.asset_count ?? 0,
});

/** 将后端 ApiAssetItem 映射为前端 AssetItem */
const mapAsset = (item: ApiAssetItem): AssetItem => {
  const { status, label } = inferStatus(
    item.quality_score ?? undefined,
    item.classification_status ?? undefined,
  );
  const metadata = item.metadata || {};
  const kind = inferKind(item.mime_type || "");
  return {
    id: item.id,
    name: item.name,
    kind,
    // 视频类型不能用 file_url 做缩略图（是视频文件，<img> 无法渲染）
    thumbUrl:
      (item.thumbnail_url as string | undefined) ||
      (metadata.thumbnail_url as string | undefined) ||
      (kind !== "video" ? (item.file_url as string | undefined) : undefined),
    fileUrl:
      (item.file_url as string | undefined) ||
      (metadata.file_url as string | undefined),
    status,
    statusLabel: label,
    duration:
      metadata.duration != null
        ? formatDuration(metadata.duration as number)
        : undefined,
    size: item.file_size ? +(item.file_size / (1024 * 1024)).toFixed(1) : 0,
    createdAt: item.created_at
      ? new Date(item.created_at).toISOString().slice(0, 10)
      : "—",
  };
};

/* ============================================================
 * 常量
 * ============================================================ */
const MAX_FILE_SIZE = 2048 * 1024 * 1024;
const LARGE_FILE_THRESHOLD = 100 * 1024 * 1024;

/* ============================================================
 * 工具函数
 * ============================================================ */
const kindIcon = (kind: AssetKind) => {
  switch (kind) {
    case "video":
      return <VideoCameraOutlined />;
    case "image":
      return <PictureOutlined />;
  }
};

const kindLabel = (kind: AssetKind) => {
  switch (kind) {
    case "video":
      return "视频";
    case "image":
      return "图片";
  }
};

/** 根据素材类型返回渐变背景 */
const thumbGradient = (kind: AssetKind): string => {
  switch (kind) {
    case "video":
      return "linear-gradient(135deg, #312e81 0%, #4f46e5 50%, #6366f1 100%)";
    case "image":
      return "linear-gradient(135deg, #78350f 0%, #d97706 50%, #f59e0b 100%)";
  }
};

/* ============================================================
 * StatusPill 组件
 * ============================================================ */
const StatusPill: React.FC<{ status: StatusType; label: string }> = ({
  status,
  label,
}) => (
  <span className={`xx-status-pill xx-status-pill-${status}`}>{label}</span>
);

/* ============================================================
 * SkeletonCard — 骨架屏卡片（素材列表加载时占位）
 * ============================================================ */
const SkeletonCard: React.FC = () => (
  <div className="xx-asset-card xx-asset-skeleton">
    <div className="xx-asset-thumb xx-skeleton-pulse" />
    <div className="xx-asset-info">
      <div
        className="xx-skeleton-line xx-skeleton-pulse"
        style={{ width: "70%" }}
      />
      <div
        className="xx-skeleton-line xx-skeleton-pulse"
        style={{ width: "40%", marginTop: 8 }}
      />
      <div
        className="xx-skeleton-line xx-skeleton-pulse"
        style={{
          width: "100%",
          height: 28,
          marginTop: 8,
          borderRadius: "var(--radius-xs)",
        }}
      />
    </div>
  </div>
);

/* ============================================================
 * AssetCard 组件
 * ============================================================ */
const AssetCard: React.FC<{
  asset: AssetItem;
  selected: boolean;
  diagnosing?: boolean;
  onToggle: () => void;
  onDiagnose: () => void;
  onPlay: () => void;
}> = ({ asset, selected, diagnosing, onToggle, onDiagnose, onPlay }) => (
  <div
    className={`xx-asset-card${selected ? " xx-asset-card-selected" : ""}`}
    onClick={onToggle}
  >
    {/* 缩略图区 */}
    <div
      className="xx-asset-thumb"
      style={{ background: thumbGradient(asset.kind) }}
    >
      {asset.thumbUrl ? (
        <img src={asset.thumbUrl} alt={asset.name} />
      ) : (
        <span className="xx-asset-thumb-placeholder">
          {kindIcon(asset.kind)}
        </span>
      )}

      {/* 视频/配音类显示播放按钮 */}
      {asset.kind === "video" && (
        <span
          className="xx-asset-play"
          onClick={(e) => {
            e.stopPropagation();
            onPlay();
          }}
        >
          <PlayCircleOutlined />
        </span>
      )}

      {/* 选中态勾选 */}
      {selected && (
        <span className="xx-asset-check">
          <CheckOutlined />
        </span>
      )}
    </div>

    {/* 信息区 */}
    <div className="xx-asset-info">
      <p className="xx-asset-name" title={asset.name}>
        {asset.name}
      </p>
      <div className="xx-asset-meta">
        <StatusPill status={asset.status} label={asset.statusLabel} />
        {asset.duration && <span>{asset.duration}</span>}
      </div>
      <button
        className={`xx-asset-diagnose-btn${diagnosing ? " xx-asset-diagnose-btn-loading" : ""}`}
        disabled={diagnosing}
        onClick={(e) => {
          e.stopPropagation();
          onDiagnose();
        }}
      >
        {diagnosing ? <LoadingOutlined /> : <ExperimentOutlined />}
        {diagnosing ? "诊断中..." : "诊断"}
      </button>
    </div>
  </div>
);

/* ============================================================
 * 主组件
 * ============================================================ */
const AssetLibrary: React.FC = () => {
  const queryClient = useQueryClient();

  /* ── 获取素材库列表 ── */
  const { data: apiLibraries = [], isLoading: libLoading } = useQuery<
    AssetLibraryItem[],
    Error
  >({
    queryKey: ["asset-libraries"],
    queryFn: getAssetLibraries,
    staleTime: 60_000,
  });

  const libraries = useMemo(() => apiLibraries.map(mapLibrary), [apiLibraries]);

  /* ── 当前选中的素材库 ── */
  const [activeLibId, setActiveLibId] = useState<string>("");

  // 当库列表加载完成后，自动选中第一个
  const effectiveLibId = activeLibId || libraries[0]?.id || "";

  /* ── 获取当前库的素材列表 ── */
  const {
    data: apiAssets = [],
    isLoading: assetsLoading,
    isError: assetsError,
    error: assetsErrorObj,
    refetch: refetchAssets,
  } = useQuery<ApiAssetItem[], Error>({
    queryKey: ["assets", effectiveLibId],
    queryFn: () => getAssets(effectiveLibId),
    enabled: !!effectiveLibId,
    staleTime: 30_000,
  });

  const assets = useMemo(() => apiAssets.map(mapAsset), [apiAssets]);

  /* ── Mutations ── */
  const createLibMutation = useMutation({
    mutationFn: createAssetLibrary,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["asset-libraries"] });
      message.success("素材库创建成功");
    },
    onError: () => {
      message.error("创建素材库失败");
    },
  });

  const deleteLibMutation = useMutation({
    mutationFn: deleteAssetLibrary,
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["asset-libraries"] });
      message.success("素材库已删除");
    },
    onError: () => {
      message.error("删除素材库失败");
    },
  });

  /* 状态 */
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());

  /* 筛选 */
  const [searchText, setSearchText] = useState("");
  const [filterType, setFilterType] = useState<string>("all");
  const [filterTime, setFilterTime] = useState<string>("all");

  /* 上传 */
  const [uploading, setUploading] = useState(false);
  const [uploadProgress, setUploadProgress] = useState(0);

  /* 新建素材库 */
  const [createModalOpen, setCreateModalOpen] = useState(false);
  const [newLibName, setNewLibName] = useState("");
  const [newLibKind, setNewLibKind] = useState<AssetKind>("video");

  /* 视频播放 */
  const [playingAsset, setPlayingAsset] = useState<AssetItem | null>(null);

  /* 诊断中状态 — 记录正在诊断的素材 ID */
  const [diagnosingId, setDiagnosingId] = useState<string | null>(null);

  /* 派生数据 */
  const filteredAssets = useMemo(() => {
    let list = assets;

    /* 按素材库类型过滤（如果筛选类型不是 all） */
    if (filterType !== "all") {
      list = list.filter((a) => a.kind === filterType);
    }

    /* 按时间筛选 */
    if (filterTime !== "all") {
      const now = new Date();
      list = list.filter((a) => {
        const d = new Date(a.createdAt);
        const diffDays = (now.getTime() - d.getTime()) / (1000 * 60 * 60 * 24);
        if (filterTime === "today") return diffDays < 1;
        if (filterTime === "week") return diffDays < 7;
        if (filterTime === "month") return diffDays < 30;
        return true;
      });
    }

    /* 搜索 */
    if (searchText.trim()) {
      const q = searchText.trim().toLowerCase();
      list = list.filter((a) => a.name.toLowerCase().includes(q));
    }

    return list;
  }, [assets, filterType, filterTime, searchText]);

  /* 选择操作 */
  const toggleSelect = (id: string) => {
    setSelectedIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  };

  const selectAll = () => {
    setSelectedIds(new Set(filteredAssets.map((a) => a.id)));
  };

  const deselectAll = () => {
    setSelectedIds(new Set());
  };

  /* 上传 — 调用真实 API */
  const handleUpload = async (file: File) => {
    if (file.size > MAX_FILE_SIZE) {
      message.error(`文件 "${file.name}" 超过 2GB 限制`);
      return false;
    }
    if (!effectiveLibId) {
      message.warning("请先选择或创建一个素材库");
      return false;
    }

    setUploading(true);
    setUploadProgress(0);
    try {
      if (file.size > LARGE_FILE_THRESHOLD) {
        message.info(`大文件 "${file.name}" 将使用直传上传`);
      }
      await uploadAssetDirect({
        file,
        library_id: effectiveLibId,
        onProgress: (pct) => setUploadProgress(pct),
      });
      message.success(`"${file.name}" 上传成功`);
      queryClient.invalidateQueries({ queryKey: ["assets"] });
      queryClient.invalidateQueries({ queryKey: ["asset-libraries"] });
    } catch (err: unknown) {
      const detail = err instanceof Error ? err.message : "";
      message.error(`"${file.name}" 上传失败${detail ? `：${detail}` : ""}`);
    } finally {
      setUploading(false);
      setUploadProgress(0);
    }
    return false;
  };

  /* 新建素材库 */
  const handleCreateLibrary = async () => {
    if (!newLibName.trim()) {
      message.warning("请输入素材库名称");
      return;
    }
    try {
      const newLib = await createLibMutation.mutateAsync({
        name: newLibName.trim(),
        kind: newLibKind,
      });
      setActiveLibId(newLib.id);
      setCreateModalOpen(false);
      setNewLibName("");
      setNewLibKind("video");
    } catch {
      // error handled in mutation
    }
  };

  /* 删除素材库 */
  const handleDeleteLibrary = async (id: string) => {
    try {
      await deleteLibMutation.mutateAsync(id);
      if (effectiveLibId === id) {
        const remaining = libraries.filter((l) => l.id !== id);
        if (remaining.length > 0) setActiveLibId(remaining[0].id);
        else setActiveLibId("");
      }
    } catch {
      // error handled in mutation
    }
  };

  /* 诊断 — 调用真实 API，带 loading 状态 */
  const handleDiagnose = async (asset: AssetItem) => {
    setDiagnosingId(asset.id);
    try {
      const result = await getAssetDiagnosis(asset.id);
      const score = result.readiness_score ?? "-";
      message.success(`"${asset.name}" 诊断完成，就绪分：${score}`);
      queryClient.invalidateQueries({ queryKey: ["assets"] });
    } catch {
      message.error(`"${asset.name}" 诊断失败`);
    } finally {
      setDiagnosingId(null);
    }
  };

  /* 批量删除 */
  const handleBatchDelete = async () => {
    const ids = Array.from(selectedIds);
    let successCount = 0;
    for (const id of ids) {
      try {
        await deleteAsset(id);
        successCount++;
      } catch {
        // 忽略单个失败
      }
    }
    queryClient.invalidateQueries({ queryKey: ["assets"] });
    queryClient.invalidateQueries({ queryKey: ["asset-libraries"] });
    setSelectedIds(new Set());
    message.success(`已删除 ${successCount}/${ids.length} 个素材`);
  };

  // ── Loading 状态 ──
  if (libLoading) {
    return (
      <div className="xx-assets-page">
        <div className="xx-assets-skeleton-grid">
          {Array.from({ length: 8 }).map((_, i) => (
            <SkeletonCard key={i} />
          ))}
        </div>
      </div>
    );
  }

  return (
    <div className="xx-assets-page">
      {/* ─── 上传进度弹窗（圆形动画 + 百分比） ─── */}
      <AntModal
        open={uploading}
        footer={null}
        closable={false}
        centered
        width={260}
        maskClosable={false}
        className="xx-upload-progress-modal"
      >
        <div className="xx-upload-progress-body">
          <svg
            className="xx-upload-progress-ring"
            viewBox="0 0 120 120"
            width={120}
            height={120}
          >
            {/* 背景圆环 */}
            <circle
              cx="60"
              cy="60"
              r="52"
              fill="none"
              stroke="var(--border-primary, #e5e7eb)"
              strokeWidth="8"
            />
            {/* 进度圆弧 */}
            <circle
              cx="60"
              cy="60"
              r="52"
              fill="none"
              stroke="var(--primary-color, #6366f1)"
              strokeWidth="8"
              strokeLinecap="round"
              strokeDasharray={`${2 * Math.PI * 52}`}
              strokeDashoffset={`${2 * Math.PI * 52 * (1 - uploadProgress / 100)}`}
              transform="rotate(-90 60 60)"
              style={{ transition: "stroke-dashoffset 0.3s ease" }}
            />
          </svg>
          <div className="xx-upload-progress-text">
            <span className="xx-upload-progress-pct">{uploadProgress}%</span>
            <span className="xx-upload-progress-label">上传中…</span>
          </div>
        </div>
      </AntModal>

      {/* 两栏布局 */}
      <div className="xx-assets-layout">
        {/* ─── 左侧：素材库列表 ─── */}
        <div className="xx-asset-library-list">
          {libraries.map((lib) => (
            <div
              key={lib.id}
              className={`xx-asset-library-item${lib.id === effectiveLibId ? " active" : ""}`}
              onClick={() => setActiveLibId(lib.id)}
            >
              <div className="xx-asset-library-header">
                <h4>
                  {kindIcon(lib.kind)} {lib.name}
                </h4>
                <Popconfirm
                  title={`确定删除素材库 "${lib.name}"？`}
                  onConfirm={(e) => {
                    e?.stopPropagation();
                    handleDeleteLibrary(lib.id);
                  }}
                  onCancel={(e) => e?.stopPropagation()}
                  okText="删除"
                  cancelText="取消"
                >
                  <button
                    className="xx-asset-library-delete"
                    onClick={(e) => e.stopPropagation()}
                    title="删除素材库"
                  >
                    <DeleteOutlined />
                  </button>
                </Popconfirm>
              </div>
              <span>
                {kindLabel(lib.kind)} · {lib.count} 个素材
              </span>
            </div>
          ))}

          {/* 新建素材库 */}
          <div
            className="xx-asset-library-add"
            onClick={() => setCreateModalOpen(true)}
          >
            <PlusOutlined />
            新建素材库
          </div>
        </div>

        {/* ─── 右侧：内容区 ─── */}
        <div className="xx-assets-content">
          {/* 上传区域 */}
          <Upload.Dragger
            beforeUpload={handleUpload}
            showUploadList={false}
            multiple
            accept="video/*,image/*"
          >
            <div className="xx-asset-upload-zone">
              <p className="xx-asset-upload-icon">
                <InboxOutlined />
              </p>
              <p className="xx-asset-upload-text">
                {uploading ? "上传中..." : "点击或拖拽文件到此区域上传"}
              </p>
              <p className="xx-asset-upload-hint">
                支持视频、图片，单文件不超过 2GB
              </p>
            </div>
          </Upload.Dragger>

          {/* 筛选栏 */}
          <div className="xx-assets-filters">
            <div className="xx-assets-filters-left">
              <Input
                placeholder="搜索素材名称..."
                prefix={<SearchOutlined />}
                value={searchText}
                onChange={(e) => setSearchText(e.target.value)}
                allowClear
                style={{ width: 220 }}
              />
              <Select
                value={filterType}
                onChange={setFilterType}
                style={{ width: 120 }}
                options={[
                  { value: "all", label: "全部类型" },
                  { value: "video", label: "视频" },
                  { value: "image", label: "图片" },
                ]}
              />
              <Select
                value={filterTime}
                onChange={setFilterTime}
                style={{ width: 120 }}
                options={[
                  { value: "all", label: "全部时间" },
                  { value: "today", label: "今天" },
                  { value: "week", label: "近一周" },
                  { value: "month", label: "近一月" },
                ]}
              />
            </div>
            <div className="xx-assets-filters-right">
              <Button buttonType="ghost" buttonSize="sm" onClick={selectAll}>
                全选
              </Button>
              <span className="xx-assets-filter-count">
                共 {filteredAssets.length} 个素材
              </span>
            </div>
          </div>

          {/* 批量操作栏 */}
          {selectedIds.size > 0 && (
            <div className="xx-assets-batch-bar">
              <span className="xx-assets-batch-count">
                已选 {selectedIds.size} 项
              </span>
              <Button buttonType="ghost" buttonSize="sm" onClick={deselectAll}>
                取消选择
              </Button>
              <Popconfirm
                title={`确定删除 ${selectedIds.size} 个素材？`}
                onConfirm={handleBatchDelete}
                okText="删除"
                cancelText="取消"
              >
                <Button
                  buttonType="danger"
                  buttonSize="sm"
                  icon={<DeleteOutlined />}
                >
                  批量删除
                </Button>
              </Popconfirm>
            </div>
          )}

          {/* 素材网格 */}
          {assetsLoading ? (
            <div className="xx-asset-grid">
              {Array.from({ length: 8 }).map((_, i) => (
                <SkeletonCard key={i} />
              ))}
            </div>
          ) : assetsError ? (
            <div className="xx-assets-empty">
              <div className="xx-assets-empty-icon">
                <ExclamationCircleOutlined />
              </div>
              <p className="xx-assets-empty-title">
                {assetsErrorObj?.message || "加载失败"}
              </p>
              <Button
                buttonType="primary"
                buttonSize="sm"
                onClick={() => refetchAssets()}
              >
                重新加载
              </Button>
            </div>
          ) : filteredAssets.length > 0 ? (
            <div className="xx-asset-grid">
              {filteredAssets.map((asset) => (
                <AssetCard
                  key={asset.id}
                  asset={asset}
                  selected={selectedIds.has(asset.id)}
                  diagnosing={diagnosingId === asset.id}
                  onToggle={() => toggleSelect(asset.id)}
                  onDiagnose={() => handleDiagnose(asset)}
                  onPlay={() => setPlayingAsset(asset)}
                />
              ))}
            </div>
          ) : (
            <div className="xx-assets-empty">
              <div className="xx-assets-empty-icon">
                <PictureOutlined />
              </div>
              <p className="xx-assets-empty-title">
                暂无素材，请上传或切换素材库
              </p>
            </div>
          )}
        </div>
      </div>

      {/* ─── 新建素材库弹窗 ─── */}
      <AntModal
        title="新建素材库"
        open={createModalOpen}
        onCancel={() => setCreateModalOpen(false)}
        onOk={handleCreateLibrary}
        okText="创建"
        cancelText="取消"
        destroyOnClose
        confirmLoading={createLibMutation.isPending}
      >
        <div className="xx-asset-form-body">
          <div>
            <div className="xx-asset-form-label">名称</div>
            <Input
              placeholder="请输入素材库名称"
              value={newLibName}
              onChange={(e) => setNewLibName(e.target.value)}
              maxLength={50}
            />
          </div>
          <div>
            <div className="xx-asset-form-label">类型</div>
            <Select
              value={newLibKind}
              onChange={(v) => setNewLibKind(v)}
              style={{ width: "100%" }}
              options={[
                { value: "video", label: "视频" },
                { value: "image", label: "图片" },
              ]}
            />
          </div>
        </div>
      </AntModal>

      {/* ─── 视频/音频播放弹窗 ─── */}
      <AntModal
        title={playingAsset?.name ?? "播放"}
        open={!!playingAsset}
        onCancel={() => setPlayingAsset(null)}
        footer={null}
        width={640}
        destroyOnClose
      >
        {playingAsset?.fileUrl ? (
          <video
            src={playingAsset.fileUrl}
            controls
            autoPlay
            className="xx-asset-video-player"
          />
        ) : (
          <div className="xx-asset-empty-fallback">
            <p>暂无可播放的文件地址</p>
            <p className="xx-asset-empty-fallback-id">
              素材 ID: {playingAsset?.id}
            </p>
          </div>
        )}
      </AntModal>
    </div>
  );
};

export default AssetLibrary;
