/**
 * 工作区路径验证模块
 * 参考 Cline 的路径安全检查机制
 */

import * as os from 'os';
import * as path from 'path';
import type { PathValidationResult } from './types.js';

/**
 * 工作区路径验证器
 * 阻止在敏感目录（home、desktop、documents 等）创建检查点
 */
export class WorkspacePathValidator {
  private blockedPaths: string[];
  private blockedPathsLower: string[];

  constructor() {
    const home = os.homedir();

    this.blockedPaths = [
      // Home 目录
      home,
      // 常见敏感目录
      path.join(home, 'Desktop'),
      path.join(home, 'Documents'),
      path.join(home, 'Downloads'),
      path.join(home, 'Pictures'),
      path.join(home, 'Music'),
      path.join(home, 'Videos'),
      // 系统根目录
      '/',
      '/tmp',
      '/var',
      '/etc',
      '/usr',
      '/bin',
      '/sbin',
      '/opt',
    ];

    // Windows 特殊路径
    if (process.platform === 'win32') {
      this.blockedPaths.push(
        'C:\\',
        'C:\\Windows',
        'C:\\Windows\\System32',
        'C:\\Program Files',
        'C:\\Program Files (x86)',
        'C:\\Users',
        'C:\\ProgramData'
      );
    }

    // macOS 特殊路径
    if (process.platform === 'darwin') {
      this.blockedPaths.push(
        '/Applications',
        '/System',
        '/Library',
        path.join(home, 'Library')
      );
    }

    // 创建小写版本用于不区分大小写的比较
    this.blockedPathsLower = this.blockedPaths.map((p) => p.toLowerCase());
  }

  /**
   * 验证工作目录是否安全
   */
  validate(workDir: string): PathValidationResult {
    const normalizedPath = path.resolve(workDir);
    const normalizedLower = normalizedPath.toLowerCase();

    // 1. 检查是否为阻止的路径
    for (let i = 0; i < this.blockedPaths.length; i++) {
      const blocked = this.blockedPaths[i];
      const blockedLower = this.blockedPathsLower[i];

      // 精确匹配
      if (
        normalizedPath === blocked ||
        normalizedLower === blockedLower
      ) {
        return {
          valid: false,
          reason: `Cannot create checkpoints in "${blocked}" - this is a protected directory`,
        };
      }
    }

    // 2. 检查是否为系统目录的直接子目录
    if (this.isDirectChildOfBlocked(normalizedPath)) {
      return {
        valid: false,
        reason: `Cannot create checkpoints directly under system directories`,
      };
    }

    // 3. 检查路径是否过短（可能是根目录或系统目录）
    const pathDepth = this.getPathDepth(normalizedPath);
    if (pathDepth < 2) {
      return {
        valid: false,
        reason: 'Path is too shallow - please use a project subdirectory',
      };
    }

    // 4. 检查是否包含危险字符
    if (this.containsDangerousChars(normalizedPath)) {
      return {
        valid: false,
        reason: 'Path contains invalid characters',
      };
    }

    return { valid: true };
  }

  /**
   * 检查是否为阻止路径的直接子目录
   */
  private isDirectChildOfBlocked(targetPath: string): boolean {
    const parent = path.dirname(targetPath);
    const parentLower = parent.toLowerCase();

    for (let i = 0; i < this.blockedPaths.length; i++) {
      if (
        parent === this.blockedPaths[i] ||
        parentLower === this.blockedPathsLower[i]
      ) {
        // 特殊情况：允许 home 目录下的项目目录
        const home = os.homedir();
        if (parent === home || parentLower === home.toLowerCase()) {
          // 但不允许一些特定的目录名
          const dirName = path.basename(targetPath).toLowerCase();
          const protectedNames = [
            'desktop',
            'documents',
            'downloads',
            'pictures',
            'music',
            'videos',
            'library',
            '.trash',
            '.cache',
          ];
          if (!protectedNames.includes(dirName)) {
            return false; // 允许 home 下的其他目录
          }
        }
        return true;
      }
    }

    return false;
  }

  /**
   * 获取路径深度
   */
  private getPathDepth(targetPath: string): number {
    const normalized = path.normalize(targetPath);
    const parts = normalized.split(path.sep).filter((p) => p.length > 0);

    // Windows 盘符算一层
    if (process.platform === 'win32' && /^[A-Za-z]:$/.test(parts[0] || '')) {
      return parts.length - 1;
    }

    return parts.length;
  }

  /**
   * 检查是否包含危险字符
   */
  private containsDangerousChars(targetPath: string): boolean {
    // 检查空字节和其他控制字符
    if (/[\x00-\x1f]/.test(targetPath)) {
      return true;
    }

    // 检查 .. 路径遍历
    if (targetPath.includes('..')) {
      const resolved = path.resolve(targetPath);
      if (resolved !== targetPath) {
        return true;
      }
    }

    return false;
  }

  /**
   * 获取阻止的路径列表
   */
  getBlockedPaths(): string[] {
    return [...this.blockedPaths];
  }

  /**
   * 添加自定义阻止路径
   */
  addBlockedPath(blockedPath: string): void {
    const normalized = path.resolve(blockedPath);
    if (!this.blockedPaths.includes(normalized)) {
      this.blockedPaths.push(normalized);
      this.blockedPathsLower.push(normalized.toLowerCase());
    }
  }

  /**
   * 检查路径是否为有效的项目目录
   * 额外检查是否包含常见的项目标识文件
   */
  async isProjectDirectory(workDir: string): Promise<boolean> {
    const fs = await import('fs/promises');

    const projectIndicators = [
      'package.json',
      'Cargo.toml',
      'go.mod',
      'pom.xml',
      'build.gradle',
      'requirements.txt',
      'setup.py',
      'pyproject.toml',
      'Gemfile',
      'composer.json',
      '.git',
      'Makefile',
      'CMakeLists.txt',
    ];

    for (const indicator of projectIndicators) {
      try {
        await fs.access(path.join(workDir, indicator));
        return true;
      } catch {
        // 继续检查下一个
      }
    }

    return false;
  }
}

/**
 * 创建路径验证器实例
 */
export function createPathValidator(): WorkspacePathValidator {
  return new WorkspacePathValidator();
}
