import { describe, it, expect, beforeEach, vi } from 'vitest';
import {
  PermissionManager,
  getPermissionManager,
  resetPermissionManager,
} from '../../../src/permission/manager.js';
import type { PermissionDecision, PermissionContext } from '../../../src/permission/types.js';

// Mock 检查器以避免文件系统操作
vi.mock('fs', () => ({
  existsSync: vi.fn(() => false),
  readFileSync: vi.fn(),
  writeFileSync: vi.fn(),
  mkdirSync: vi.fn(),
}));

vi.mock('../../../src/permission/file-prompt.js', () => ({
  promptFilePermission: vi.fn().mockResolvedValue({ allow: true, remember: false }),
}));

describe('PermissionManager - 权限管理器', () => {
  let manager: PermissionManager;
  const testProjectRoot = '/test/project';

  beforeEach(() => {
    manager = new PermissionManager(testProjectRoot);
    vi.clearAllMocks();
  });

  describe('初始化', () => {
    it('创建时注册默认检查器', () => {
      // 应该包含 bash, file, web, git 检查器
      expect(manager.getChecker('bash')).toBeDefined();
      expect(manager.getChecker('file')).toBeDefined();
      expect(manager.getChecker('web')).toBeDefined();
      expect(manager.getChecker('git')).toBeDefined();
    });

    it('未注册的检查器返回 undefined', () => {
      expect(manager.getChecker('non-existent')).toBeUndefined();
    });
  });

  describe('registerChecker', () => {
    it('注册自定义检查器', () => {
      const customChecker = {
        name: 'custom',
        check: vi.fn().mockResolvedValue({ allowed: true, action: 'allow' }),
        clearSessionPermissions: vi.fn(),
      };

      manager.registerChecker(customChecker);

      expect(manager.getChecker('custom')).toBe(customChecker);
    });

    it('覆盖已有检查器', () => {
      const newBashChecker = {
        name: 'bash',
        check: vi.fn().mockResolvedValue({ allowed: false, action: 'deny' }),
        clearSessionPermissions: vi.fn(),
      };

      manager.registerChecker(newBashChecker);

      expect(manager.getChecker('bash')).toBe(newBashChecker);
    });
  });

  describe('setAskCallback', () => {
    it('设置回调传递给所有支持回调的检查器', () => {
      const callback = vi.fn().mockResolvedValue({
        allow: true,
        remember: false,
      } as PermissionDecision);

      manager.setAskCallback(callback);

      // 验证回调被设置（通过间接方式）
      expect(callback).not.toHaveBeenCalled(); // 设置时不调用
    });
  });

  describe('checkPermission', () => {
    it('使用指定检查器检查权限', async () => {
      const result = await manager.checkPermission('bash', {
        command: 'ls -la',
        workdir: testProjectRoot,
      });

      expect(result.allowed).toBe(true);
    });

    it('未注册的检查器返回 ask', async () => {
      const result = await manager.checkPermission('non-existent', {
        command: 'some command',
        workdir: testProjectRoot,
      });

      expect(result.action).toBe('ask');
      expect(result.needsConfirmation).toBe(true);
      expect(result.reason).toContain('未找到检查器');
    });
  });

  describe('checkBashPermission - 便捷方法', () => {
    it('检查安全命令', async () => {
      const result = await manager.checkBashPermission({
        command: 'git status',
        workdir: testProjectRoot,
      });

      expect(result.allowed).toBe(true);
    });

    it('检查危险命令', async () => {
      const result = await manager.checkBashPermission({
        command: 'rm -rf /',
        workdir: testProjectRoot,
      });

      expect(result.allowed).toBe(false);
    });
  });

  describe('checkFilePermission - 便捷方法', () => {
    it('检查读操作', async () => {
      const result = await manager.checkFilePermission({
        operation: 'read',
        path: './src/index.ts',
        workdir: testProjectRoot,
      });

      expect(result.allowed).toBe(true);
    });

    it('检查写操作需要确认', async () => {
      const result = await manager.checkFilePermission({
        operation: 'write',
        path: './src/new-file.ts',
        workdir: testProjectRoot,
      });

      expect(result.action).toBe('ask');
    });
  });

  describe('checkGitPermission - 便捷方法', () => {
    it('检查读操作', async () => {
      const result = await manager.checkGitPermission({
        operation: 'status',
      });

      expect(result.allowed).toBe(true);
    });

    it('检查写操作需要确认', async () => {
      const result = await manager.checkGitPermission({
        operation: 'push',
      });

      expect(result.action).toBe('ask');
    });
  });

  describe('checkWebPermission - 便捷方法', () => {
    it('检查网页访问', async () => {
      const result = await manager.checkWebPermission({
        operation: 'fetch',
        url: 'https://example.com',
      });

      // Web 检查器的默认行为
      expect(result).toBeDefined();
    });
  });

  describe('会话权限管理', () => {
    it('clearAllSessionPermissions 清除所有检查器的权限', () => {
      // 调用方法不应该抛出错误
      expect(() => manager.clearAllSessionPermissions()).not.toThrow();
    });

    it('clearSessionPermissions 清除指定检查器的权限', () => {
      expect(() => manager.clearSessionPermissions('bash')).not.toThrow();
      expect(() => manager.clearSessionPermissions('file')).not.toThrow();
      expect(() => manager.clearSessionPermissions('git')).not.toThrow();
    });

    it('清除不存在的检查器权限不报错', () => {
      expect(() => manager.clearSessionPermissions('non-existent')).not.toThrow();
    });
  });
});

describe('全局实例管理', () => {
  beforeEach(() => {
    resetPermissionManager();
  });

  it('getPermissionManager 返回单例', () => {
    const manager1 = getPermissionManager('/test/project');
    const manager2 = getPermissionManager();

    expect(manager1).toBe(manager2);
  });

  it('resetPermissionManager 重置单例', () => {
    const manager1 = getPermissionManager('/test/project');
    resetPermissionManager();
    const manager2 = getPermissionManager('/test/project');

    expect(manager1).not.toBe(manager2);
  });

  it('首次创建使用指定的 projectRoot', () => {
    const manager = getPermissionManager('/custom/root');

    // 验证管理器已创建
    expect(manager).toBeDefined();
  });
});
