/**
 * 项目元数据工具函数
 * ==================
 *
 * 封装 meta.json 的构建、合并、迁移逻辑。
 * 新增字段时只需在 types/project.ts 的 ProjectMeta 中定义，
 * 此处无需修改。
 */

import type { ProjectMeta, MetaOverrides } from '../types/project';

// ------------------------------------------------------------------
// 默认值配置（集中管理）
// ------------------------------------------------------------------

const DEFAULT_META_VALUES: Partial<ProjectMeta> = {
  currentStep: 1,
  voiceSpeed: 1.0,
  voiceVolume: 0,
  voicePitch: 0,
  status: 'draft',
  version: 1,
};

// ------------------------------------------------------------------
// 内部工具：判断值是否为 undefined（区分"未传"和"传了 undefined"）
// ------------------------------------------------------------------

function hasOwn<K extends string>(obj: object, key: K): obj is Record<K, unknown> {
  return Object.prototype.hasOwnProperty.call(obj, key);
}

// ------------------------------------------------------------------
// 构建项目标题
// ------------------------------------------------------------------

function buildTitle(topic: string | undefined, existingTitle?: string): string {
  // 优先保留用户自定义的项目名称
  if (existingTitle) {
    return existingTitle;
  }
  const trimmed = topic?.trim();
  if (trimmed) {
    return trimmed;
  }
  return '未命名项目';
}

// ------------------------------------------------------------------
// 核心：通用元数据合并函数
// ------------------------------------------------------------------

/**
 * 构建完整的 ProjectMeta 对象。
 *
 * 逻辑：
 * 1. 将 existingMeta 与 overrides 合并（overrides 优先级高）
 * 2. 计算系统字段（id, title, status, timestamps）
 * 3. 填充默认值
 *
 * @param projectId   项目 ID
 * @param existing    磁盘上已有的 meta（可能为 null）
 * @param overrides   前端传入的覆盖值
 */
export function buildProjectMeta(
  projectId: string,
  existing: Partial<ProjectMeta> | null,
  overrides: MetaOverrides = {},
): ProjectMeta {
  const now = Date.now();

  // Step 1: 自动合并所有非系统字段
  const merged: Partial<ProjectMeta> = { ...(existing || {}) };

  for (const key of Object.keys(overrides) as Array<keyof MetaOverrides>) {
    if (hasOwn(overrides, key)) {
      (merged as Record<string, unknown>)[key] = overrides[key];
    }
  }

  // Step 2: 计算系统字段
  const topic = merged.topic;
  const title = buildTitle(topic, merged.title);

  // Step 3: 组装最终结果
  return {
    // 系统字段（不能被 overrides 覆盖）
    id: projectId,
    title,
    status: (merged.status as 'draft' | 'published') || DEFAULT_META_VALUES.status!,
    currentStep:
      merged.currentStep ?? existing?.currentStep ?? DEFAULT_META_VALUES.currentStep!,
    createdAt: existing?.createdAt || now,
    updatedAt: now,
    version:
      (existing?.version || 0) >= 1 ? existing!.version : DEFAULT_META_VALUES.version,

    // 自动展开所有持久化字段（包括用户覆盖的和已有磁盘数据）
    ...merged,
  } as ProjectMeta;
}

// ------------------------------------------------------------------
// 数据迁移
// ------------------------------------------------------------------

/**
 * 将旧版 meta.json 升级到新格式。
 *
 * 未来结构变更时在此添加迁移逻辑：
 *   if (version < 2) { ...v1→v2 迁移... }
 */
export function migrateMeta(raw: unknown): Partial<ProjectMeta> {
  if (typeof raw !== 'object' || raw === null) {
    return {};
  }
  const obj = raw as Record<string, unknown>;
  const version = typeof obj.version === 'number' ? obj.version : 0;

  if (version < 1) {
    // v0 → v1: 添加 version 字段，其他保持不变
    return { ...obj, version: 1 } as Partial<ProjectMeta>;
  }

  // 清理已废弃字段
  if ('subcategoryCode' in obj) {
    delete (obj as Record<string, unknown>).subcategoryCode;
  }

  // 当前版本，无需迁移
  return obj as Partial<ProjectMeta>;
}

// ------------------------------------------------------------------
// 空白 overrides — 用于切换项目时清空旧数据
// ------------------------------------------------------------------

/**
 * 显式将所有业务字段设为 undefined，配合 Zustand setState 使用。
 * 在 initProjectStore / createNewProject 中先展开此对象，再展开新项目的 meta，
 * 确保旧项目的字段不会残留。
 *
 * 新增字段时必须在此补充，否则切换项目时旧值会残留。
 */
export const BLANK_META_OVERRIDES: MetaOverrides = {
  topic: undefined,
  categoryCode: undefined,
  filename: undefined,
  selectedVoiceId: undefined,
  finalVideoPath: undefined,
  finalVideoDuration: undefined,
  coverPath: undefined,
  coverConfig: undefined,
  exportedAt: undefined,
  composedVideoUrl: undefined,
  composedVideoPath: undefined,
  lipSyncTaskId: undefined,
  lipSyncState: undefined,
  lipSyncedVideoPath: undefined,
  lipSyncedVideoUrl: undefined,
  dubbingAudioUrl: undefined,
  dubbingAudioPath: undefined,
  dubbingAudioDuration: undefined,
  avatarMaterialPath: undefined,
  avatarMaterialName: undefined,
  avatarMaterialDuration: undefined,
  subtitleAlignment: undefined,
  burnedVideoPath: undefined,
  mainTitle: undefined,
  subTitle: undefined,
  mainTitlePreset: undefined,
  subTitlePreset: undefined,
  captionPreset: undefined,
  userUploadedMaterials: undefined,
  stepDirtyFlags: undefined,
  bgmMusicId: undefined,
  bgmMusicTitle: undefined,
  bgmMusicPath: undefined,
  bgmVolume: undefined,
};


