/**
 * 数据迁移框架
 * 支持版本化的数据结构升级
 */

import * as fs from 'fs/promises';
import * as path from 'path';
import { Lock } from '../utils/lock.js';

type Migration = (storageDir: string) => Promise<void>;

/**
 * 迁移函数列表
 * 新迁移添加到数组末尾，索引即为版本号
 */
const MIGRATIONS: Migration[] = [
  // 迁移 0: 初始化新目录结构
  // 将旧的 sessions/ 目录下的会话文件迁移到新的分层结构
  async (storageDir: string) => {
    const oldSessionsDir = path.join(storageDir, 'sessions');
    const projectDir = path.join(storageDir, 'project');
    const sessionDir = path.join(storageDir, 'session');
    const messageDir = path.join(storageDir, 'message');

    // 确保新目录存在
    await fs.mkdir(projectDir, { recursive: true });
    await fs.mkdir(sessionDir, { recursive: true });
    await fs.mkdir(messageDir, { recursive: true });

    // 检查是否有旧数据需要迁移
    try {
      const files = await fs.readdir(oldSessionsDir);
      for (const file of files) {
        if (!file.endsWith('.json')) continue;

        const filePath = path.join(oldSessionsDir, file);
        const content = await fs.readFile(filePath, 'utf-8');
        const oldSession = JSON.parse(content);

        // 提取消息
        const messages = oldSession.messages || [];
        const sessionId = oldSession.id;

        // 创建消息目录
        const sessionMessageDir = path.join(messageDir, sessionId);
        await fs.mkdir(sessionMessageDir, { recursive: true });

        // 写入每条消息
        for (let i = 0; i < messages.length; i++) {
          const messageFile = path.join(sessionMessageDir, `${String(i + 1).padStart(4, '0')}.json`);
          await fs.writeFile(
            messageFile,
            JSON.stringify(
              {
                index: i + 1,
                ...messages[i],
                createdAt: oldSession.createdAt,
              },
              null,
              2
            ),
            'utf-8'
          );
        }

        // 创建新的会话元数据 (使用默认 projectId，后续会在 storage 中更新)
        const metadata = {
          id: sessionId,
          projectId: 'default',
          createdAt: oldSession.createdAt,
          updatedAt: oldSession.updatedAt,
          workdir: oldSession.workdir,
          title: oldSession.title,
          messageCount: messages.length,
          discoveredTools: oldSession.discoveredTools || [],
          todos: oldSession.todos || [],
          parentId: oldSession.parentId,
          agentName: oldSession.agentName,
        };

        // 写入会话元数据到默认项目目录
        const defaultProjectDir = path.join(sessionDir, 'default');
        await fs.mkdir(defaultProjectDir, { recursive: true });
        await fs.writeFile(
          path.join(defaultProjectDir, `${sessionId}.json`),
          JSON.stringify(metadata, null, 2),
          'utf-8'
        );
      }

      // 迁移 current-session.json
      const currentSessionFile = path.join(storageDir, 'current-session.json');
      try {
        const currentContent = await fs.readFile(currentSessionFile, 'utf-8');
        const currentSession = JSON.parse(currentContent);

        if (currentSession.messages) {
          const sessionId = currentSession.id;
          const messages = currentSession.messages;

          // 创建消息目录
          const sessionMessageDir = path.join(messageDir, sessionId);
          await fs.mkdir(sessionMessageDir, { recursive: true });

          // 写入每条消息
          for (let i = 0; i < messages.length; i++) {
            const messageFile = path.join(sessionMessageDir, `${String(i + 1).padStart(4, '0')}.json`);
            await fs.writeFile(
              messageFile,
              JSON.stringify(
                {
                  index: i + 1,
                  ...messages[i],
                  createdAt: currentSession.createdAt,
                },
                null,
                2
              ),
              'utf-8'
            );
          }

          // 更新 current-session.json 为只包含 sessionId
          await fs.writeFile(currentSessionFile, JSON.stringify({ sessionId }, null, 2), 'utf-8');
        }
      } catch {
        // 没有 current-session.json，忽略
      }
    } catch {
      // sessions 目录不存在，跳过迁移
    }
  },
];

/**
 * 获取当前迁移版本
 */
async function getMigrationVersion(storageDir: string): Promise<number> {
  const versionFile = path.join(storageDir, 'migration');
  try {
    const content = await fs.readFile(versionFile, 'utf-8');
    return parseInt(content.trim(), 10) || 0;
  } catch {
    return 0;
  }
}

/**
 * 保存迁移版本
 */
async function setMigrationVersion(storageDir: string, version: number): Promise<void> {
  const versionFile = path.join(storageDir, 'migration');
  await fs.writeFile(versionFile, version.toString(), 'utf-8');
}

/**
 * 执行迁移
 * 在存储初始化时调用
 */
export async function runMigrations(storageDir: string): Promise<void> {
  // 使用写锁防止并发迁移
  using _ = await Lock.write(`migration:${storageDir}`);

  const currentVersion = await getMigrationVersion(storageDir);

  for (let i = currentVersion; i < MIGRATIONS.length; i++) {
    const migration = MIGRATIONS[i];

    try {
      console.log(`[migration] Running migration ${i}...`);
      await migration(storageDir);
      await setMigrationVersion(storageDir, i + 1);
      console.log(`[migration] Migration ${i} completed`);
    } catch (error) {
      console.error(`[migration] Migration ${i} failed:`, error);
      // 迁移失败不阻塞启动，但记录错误
      // 下次启动会重试失败的迁移
      break;
    }
  }
}

/**
 * 获取迁移状态
 */
export async function getMigrationStatus(storageDir: string): Promise<{
  currentVersion: number;
  latestVersion: number;
  pendingMigrations: number;
}> {
  const currentVersion = await getMigrationVersion(storageDir);
  return {
    currentVersion,
    latestVersion: MIGRATIONS.length,
    pendingMigrations: Math.max(0, MIGRATIONS.length - currentVersion),
  };
}
