import type {
  PermissionContext,
  PermissionCheckResult,
  PermissionDecision,
  FilePermissionContext,
  WebPermissionContext,
  GitPermissionContext,
} from './types.js';
import type { PermissionChecker } from './checkers/base.js';
import { BashPermissionChecker } from './checkers/bash.js';
import { FilePermissionChecker } from './checkers/file.js';
import { WebPermissionChecker } from './checkers/web.js';
import { GitPermissionChecker } from './checkers/git.js';

/**
 * 权限管理器
 * 统一管理所有工具的权限检查
 */
export class PermissionManager {
  private checkers = new Map<string, PermissionChecker>();
  private askCallback?: (ctx: PermissionContext) => Promise<PermissionDecision>;

  constructor(projectRoot: string = process.cwd()) {
    // 注册默认的检查器
    this.registerChecker(new BashPermissionChecker(projectRoot));
    this.registerChecker(new FilePermissionChecker(projectRoot));
    this.registerChecker(new WebPermissionChecker());
    this.registerChecker(new GitPermissionChecker());
  }

  /**
   * 注册权限检查器
   */
  registerChecker(checker: PermissionChecker): void {
    this.checkers.set(checker.name, checker);

    // 如果检查器支持设置回调，传递当前的回调
    if (this.askCallback && 'setAskCallback' in checker) {
      (checker as BashPermissionChecker).setAskCallback(this.askCallback);
    }
  }

  /**
   * 获取权限检查器
   */
  getChecker<T extends PermissionChecker>(name: string): T | undefined {
    return this.checkers.get(name) as T | undefined;
  }

  /**
   * 设置权限询问回调
   */
  setAskCallback(callback: (ctx: PermissionContext) => Promise<PermissionDecision>): void {
    this.askCallback = callback;

    // 传递给所有支持回调的检查器
    for (const checker of this.checkers.values()) {
      if ('setAskCallback' in checker) {
        (checker as BashPermissionChecker).setAskCallback(callback);
      }
    }
  }

  /**
   * 检查权限（使用指定的检查器）
   */
  async checkPermission(
    checkerName: string,
    ctx: PermissionContext
  ): Promise<PermissionCheckResult> {
    const checker = this.checkers.get(checkerName);

    if (!checker) {
      // 未注册的检查器，默认需要确认
      return {
        allowed: false,
        action: 'ask',
        needsConfirmation: true,
        reason: `未找到检查器: ${checkerName}`,
      };
    }

    return checker.check(ctx);
  }

  /**
   * 检查 bash 命令权限（便捷方法）
   */
  async checkBashPermission(ctx: PermissionContext): Promise<PermissionCheckResult> {
    return this.checkPermission('bash', ctx);
  }

  /**
   * 检查文件操作权限（便捷方法）
   */
  async checkFilePermission(ctx: FilePermissionContext): Promise<PermissionCheckResult> {
    const fileChecker = this.getChecker<FilePermissionChecker>('file');
    if (!fileChecker) {
      return {
        allowed: false,
        action: 'ask',
        needsConfirmation: true,
        reason: '文件权限检查器未注册',
      };
    }
    return fileChecker.checkFilePermission(ctx);
  }

  /**
   * 检查 Web 搜索权限（便捷方法）
   */
  async checkWebPermission(ctx: WebPermissionContext): Promise<PermissionCheckResult> {
    const webChecker = this.getChecker<WebPermissionChecker>('web');
    if (!webChecker) {
      return {
        allowed: false,
        action: 'ask',
        needsConfirmation: true,
        reason: 'Web 权限检查器未注册',
      };
    }
    return webChecker.checkWebPermission(ctx);
  }

  /**
   * 检查 Git 操作权限（便捷方法）
   */
  async checkGitPermission(ctx: GitPermissionContext): Promise<PermissionCheckResult> {
    const gitChecker = this.getChecker<GitPermissionChecker>('git');
    if (!gitChecker) {
      return {
        allowed: false,
        action: 'ask',
        needsConfirmation: true,
        reason: 'Git 权限检查器未注册',
      };
    }
    return gitChecker.checkGitPermission(ctx);
  }

  /**
   * 清除所有检查器的会话权限
   */
  clearAllSessionPermissions(): void {
    for (const checker of this.checkers.values()) {
      checker.clearSessionPermissions();
    }
  }

  /**
   * 清除指定检查器的会话权限
   */
  clearSessionPermissions(checkerName: string): void {
    const checker = this.checkers.get(checkerName);
    if (checker) {
      checker.clearSessionPermissions();
    }
  }
}

// 全局实例
let globalManager: PermissionManager | null = null;

export function getPermissionManager(projectRoot?: string): PermissionManager {
  if (!globalManager) {
    globalManager = new PermissionManager(projectRoot);
  }
  return globalManager;
}

export function resetPermissionManager(): void {
  globalManager = null;
}
