import type {
  GitPermissionConfig,
  GitPermissionContext,
  GitOperation,
  PermissionCheckResult,
  PermissionDecision,
  PermissionContext,
} from '../types.js';
import type { PermissionChecker } from './base.js';

// 读操作列表
const READ_OPERATIONS: GitOperation[] = [
  'status',
  'diff',
  'log',
  'branch_list',
  'show',
];

// 写操作列表
const WRITE_OPERATIONS: GitOperation[] = [
  'add',
  'commit',
  'push',
  'pull',
  'checkout',
  'branch_create',
  'branch_delete',
  'stash',
  'stash_pop',
  'merge',
  'rebase',
];

// 危险操作（需要 force 参数的操作）
const DANGEROUS_WHEN_FORCED: GitOperation[] = [
  'push',
  'reset',
  'checkout',
  'rebase',
];

// 默认 Git 权限配置
const DEFAULT_CONFIG: GitPermissionConfig = {
  readOperations: 'allow',
  writeOperations: 'ask',
  dangerousOperations: 'ask',
};

/**
 * Git 操作权限检查器
 * 控制 Git 仓库操作的权限
 */
export class GitPermissionChecker implements PermissionChecker {
  readonly name = 'git';

  private config: GitPermissionConfig;
  private askCallback?: (ctx: PermissionContext) => Promise<PermissionDecision>;
  private sessionPermissions = new Map<string, 'allow' | 'deny'>();

  constructor() {
    this.config = { ...DEFAULT_CONFIG };
  }

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

  /**
   * 判断操作类型
   */
  private getOperationType(operation: GitOperation, force?: boolean): 'read' | 'write' | 'dangerous' {
    // 强制操作属于危险操作
    if (force && DANGEROUS_WHEN_FORCED.includes(operation)) {
      return 'dangerous';
    }

    // reset 总是危险操作
    if (operation === 'reset') {
      return 'dangerous';
    }

    if (READ_OPERATIONS.includes(operation)) {
      return 'read';
    }

    return 'write';
  }

  /**
   * 获取操作的描述
   */
  private getOperationDescription(ctx: GitPermissionContext): string {
    const { operation, target, remote, force, message } = ctx;

    const parts: string[] = [`git ${operation.replace('_', ' ')}`];

    if (force) {
      parts.push('--force');
    }

    if (target) {
      parts.push(target);
    }

    if (remote) {
      parts.push(`(remote: ${remote})`);
    }

    if (message) {
      parts.push(`"${message.substring(0, 50)}${message.length > 50 ? '...' : ''}"`);
    }

    return parts.join(' ');
  }

  /**
   * 检查 Git 操作权限
   */
  async checkGitPermission(ctx: GitPermissionContext): Promise<PermissionCheckResult> {
    const { operation, force } = ctx;
    const operationType = this.getOperationType(operation, force);
    const description = this.getOperationDescription(ctx);

    // 1. 检查会话级别的临时权限
    const sessionKey = `git_${operationType}`;
    const sessionPerm = this.sessionPermissions.get(sessionKey);
    if (sessionPerm === 'allow') {
      return {
        allowed: true,
        action: 'allow',
        reason: `本次会话已允许 Git ${operationType === 'read' ? '读' : operationType === 'write' ? '写' : '危险'}操作`,
      };
    }
    if (sessionPerm === 'deny') {
      return {
        allowed: false,
        action: 'deny',
        reason: `本次会话已拒绝 Git ${operationType === 'read' ? '读' : operationType === 'write' ? '写' : '危险'}操作`,
      };
    }

    // 2. 根据操作类型确定权限策略
    let action = this.config.writeOperations;
    if (operationType === 'read') {
      action = this.config.readOperations;
    } else if (operationType === 'dangerous') {
      action = this.config.dangerousOperations;
    }

    // 3. 处理权限决策
    if (action === 'allow') {
      return {
        allowed: true,
        action: 'allow',
        reason: operationType === 'read' ? '读操作默认允许' : '配置允许',
      };
    }

    if (action === 'deny') {
      return {
        allowed: false,
        action: 'deny',
        reason: operationType === 'dangerous' ? '危险操作默认拒绝' : '配置拒绝',
      };
    }

    // action === 'ask'
    if (!this.askCallback) {
      return {
        allowed: false,
        action: 'ask',
        needsConfirmation: true,
        reason: description,
      };
    }

    // 调用回调询问用户
    const decision = await this.askCallback({
      command: description,
      workdir: process.cwd(),
    });

    if (decision.remember) {
      this.sessionPermissions.set(sessionKey, decision.allow ? 'allow' : 'deny');
    }

    return {
      allowed: decision.allow,
      action: decision.allow ? 'allow' : 'deny',
      reason: decision.allow ? '用户允许' : '用户拒绝',
    };
  }

  /**
   * 实现 PermissionChecker 接口的 check 方法
   */
  async check(ctx: PermissionContext): Promise<PermissionCheckResult> {
    // 从 command 中解析 Git 操作
    const match = ctx.command.match(/^git[_\s]+(\w+)/);
    if (!match) {
      return {
        allowed: false,
        action: 'deny',
        reason: '无法解析 Git 操作',
      };
    }

    const operation = match[1] as GitOperation;
    return this.checkGitPermission({ operation });
  }

  /**
   * 清除会话权限
   */
  clearSessionPermissions(): void {
    this.sessionPermissions.clear();
  }

  /**
   * 获取当前配置
   */
  getConfig(): GitPermissionConfig {
    return { ...this.config };
  }

  /**
   * 更新配置
   */
  setConfig(config: Partial<GitPermissionConfig>): void {
    this.config = { ...this.config, ...config };
  }
}
