/**
 * 检查点安全检查模块
 * 参考 Aider 的 7 点安全检查机制
 */

import { exec } from 'child_process';
import { promisify } from 'util';
import type { CheckpointManager } from './manager.js';
import type { SafetyCheckResult, CheckpointMetadata } from './types.js';

const execAsync = promisify(exec);

/**
 * 检查点安全检查器
 */
export class CheckpointSafetyChecker {
  private workDir: string;

  constructor(workDir: string) {
    this.workDir = workDir;
  }

  /**
   * 在回滚前执行安全检查
   */
  async checkBeforeRollback(
    checkpoint: CheckpointMetadata,
    manager: CheckpointManager
  ): Promise<SafetyCheckResult> {
    const result: SafetyCheckResult = {
      safe: true,
      warnings: [],
      errors: [],
    };

    // 1. 检查检查点是否存在
    if (!checkpoint) {
      result.safe = false;
      result.errors.push('Checkpoint not found');
      return result;
    }

    // 2. 检查工作区是否有未保存的变更
    const hasUnsaved = await this.hasUnsavedChanges(manager);
    if (hasUnsaved) {
      result.warnings.push('Working directory has unsaved changes that will be lost');
    }

    // 3. 检查主仓库状态
    const mainRepoStatus = await this.checkMainRepoStatus();
    if (mainRepoStatus.hasChanges) {
      result.warnings.push('Main repository has uncommitted changes');
    }

    // 4. 检查是否会影响已推送的文件
    const pushedCheck = await this.checkPushedFiles(checkpoint);
    if (pushedCheck.hasPushed) {
      result.warnings.push(
        `Some changes may have been pushed to remote. Files: ${pushedCheck.files.join(', ')}`
      );
    }

    // 5. 检查时间跨度
    const age = Date.now() - checkpoint.timestamp;
    const oneDay = 24 * 60 * 60 * 1000;
    if (age > oneDay) {
      const days = Math.floor(age / oneDay);
      result.warnings.push(`Checkpoint is ${days} day(s) old`);
    }

    // 6. 检查是否为 AI 创建的检查点
    const isAiCreated = this.isAiCreatedCheckpoint(checkpoint);
    if (!isAiCreated) {
      result.warnings.push('This checkpoint was not created by AI tools');
    }

    // 7. 检查影响的文件数量
    if (checkpoint.filesChanged > 50) {
      result.warnings.push(
        `This rollback will affect ${checkpoint.filesChanged} files`
      );
    }

    return result;
  }

  /**
   * 检查工作区是否有未保存的变更
   */
  private async hasUnsavedChanges(manager: CheckpointManager): Promise<boolean> {
    try {
      // 通过 manager 检查
      const checkpoints = await manager.listCheckpoints();
      if (checkpoints.length === 0) return false;

      const latest = checkpoints[0];
      const diff = await manager.getDiff(latest.id);
      return diff.files.length > 0;
    } catch {
      return false;
    }
  }

  /**
   * 检查主仓库状态
   */
  private async checkMainRepoStatus(): Promise<{ hasChanges: boolean; isGitRepo: boolean }> {
    try {
      const { stdout } = await execAsync('git status --porcelain', {
        cwd: this.workDir,
      });
      return {
        hasChanges: stdout.trim().length > 0,
        isGitRepo: true,
      };
    } catch {
      return {
        hasChanges: false,
        isGitRepo: false,
      };
    }
  }

  /**
   * 检查是否有文件已被推送到远程
   */
  private async checkPushedFiles(
    checkpoint: CheckpointMetadata
  ): Promise<{ hasPushed: boolean; files: string[] }> {
    try {
      // 检查主仓库中自检查点时间后是否有推送
      const since = new Date(checkpoint.timestamp).toISOString();
      const { stdout } = await execAsync(
        `git log --oneline --since="${since}" --name-only origin/HEAD..HEAD 2>/dev/null || true`,
        { cwd: this.workDir }
      );

      if (!stdout.trim()) {
        return { hasPushed: false, files: [] };
      }

      // 解析文件列表
      const lines = stdout.trim().split('\n');
      const files: string[] = [];
      for (const line of lines) {
        // 跳过 commit 行（包含空格）
        if (!line.includes(' ') && line.length > 0) {
          files.push(line);
        }
      }

      return {
        hasPushed: files.length > 0,
        files: [...new Set(files)],
      };
    } catch {
      return { hasPushed: false, files: [] };
    }
  }

  /**
   * 检查是否为 AI 创建的检查点
   */
  private isAiCreatedCheckpoint(checkpoint: CheckpointMetadata): boolean {
    // AI 创建的检查点通常有 toolCall 或特定的 trigger
    const aiTriggers = [
      'tool:write_file',
      'tool:edit_file',
      'tool:delete_file',
      'tool:move_file',
      'tool:copy_file',
      'tool:bash',
      'task_start',
      'task_complete',
      'auto',
    ];

    return aiTriggers.includes(checkpoint.trigger) || !!checkpoint.toolCall;
  }

  /**
   * 格式化安全检查结果为用户友好的消息
   */
  formatResult(result: SafetyCheckResult): string {
    const lines: string[] = [];

    if (result.errors.length > 0) {
      lines.push('❌ Errors:');
      for (const error of result.errors) {
        lines.push(`   - ${error}`);
      }
    }

    if (result.warnings.length > 0) {
      lines.push('⚠️  Warnings:');
      for (const warning of result.warnings) {
        lines.push(`   - ${warning}`);
      }
    }

    if (result.safe && result.warnings.length === 0) {
      lines.push('✅ All safety checks passed');
    }

    return lines.join('\n');
  }
}

/**
 * 创建安全检查器实例
 */
export function createSafetyChecker(workDir: string): CheckpointSafetyChecker {
  return new CheckpointSafetyChecker(workDir);
}
