import { describe, it, expect, beforeEach, vi } from 'vitest';
import path from 'path';

/**
 * Note: security.ts maintains module-level state (allowed paths Set).
 * We need to reset modules and reimport for each test to get fresh state.
 */
describe('security.ts', () => {
  beforeEach(() => {
    vi.resetModules();
  });

  describe('initAllowedPaths', () => {
    it('should load ALLOWED_ROOT_DIRECTORY if set', async () => {
      process.env.ALLOWED_ROOT_DIRECTORY = '/projects';
      delete process.env.DATA_DIR;

      const { initAllowedPaths, getAllowedPaths } = await import('@automaker/platform');
      initAllowedPaths();

      const allowed = getAllowedPaths();
      expect(allowed).toContain(path.resolve('/projects'));
    });

    it('should include DATA_DIR if set', async () => {
      delete process.env.ALLOWED_ROOT_DIRECTORY;
      process.env.DATA_DIR = '/data/dir';

      const { initAllowedPaths, getAllowedPaths } = await import('@automaker/platform');
      initAllowedPaths();

      const allowed = getAllowedPaths();
      expect(allowed).toContain(path.resolve('/data/dir'));
    });

    it('should include both ALLOWED_ROOT_DIRECTORY and DATA_DIR if both set', async () => {
      process.env.ALLOWED_ROOT_DIRECTORY = '/projects';
      process.env.DATA_DIR = '/data';

      const { initAllowedPaths, getAllowedPaths } = await import('@automaker/platform');
      initAllowedPaths();

      const allowed = getAllowedPaths();
      expect(allowed).toContain(path.resolve('/projects'));
      expect(allowed).toContain(path.resolve('/data'));
      expect(allowed).toHaveLength(2);
    });

    it('should return empty array when no paths configured', async () => {
      delete process.env.ALLOWED_ROOT_DIRECTORY;
      delete process.env.DATA_DIR;

      const { initAllowedPaths, getAllowedPaths } = await import('@automaker/platform');
      initAllowedPaths();

      const allowed = getAllowedPaths();
      expect(allowed).toHaveLength(0);
    });
  });

  describe('isPathAllowed', () => {
    it('should allow paths within ALLOWED_ROOT_DIRECTORY', async () => {
      process.env.ALLOWED_ROOT_DIRECTORY = '/allowed/project';
      process.env.DATA_DIR = '';

      const { initAllowedPaths, isPathAllowed } = await import('@automaker/platform');
      initAllowedPaths();

      // Paths within allowed directory should be allowed
      expect(isPathAllowed('/allowed/project/file.txt')).toBe(true);
      expect(isPathAllowed('/allowed/project/subdir/file.txt')).toBe(true);

      // Paths outside allowed directory should be denied
      expect(isPathAllowed('/not/allowed/file.txt')).toBe(false);
      expect(isPathAllowed('/tmp/file.txt')).toBe(false);
      expect(isPathAllowed('/etc/passwd')).toBe(false);
    });

    it('should allow all paths when no restrictions are configured', async () => {
      delete process.env.DATA_DIR;
      delete process.env.ALLOWED_ROOT_DIRECTORY;

      const { initAllowedPaths, isPathAllowed } = await import('@automaker/platform');
      initAllowedPaths();

      // All paths should be allowed when no restrictions are configured
      expect(isPathAllowed('/allowed/project/file.txt')).toBe(true);
      expect(isPathAllowed('/not/allowed/file.txt')).toBe(true);
      expect(isPathAllowed('/tmp/file.txt')).toBe(true);
      expect(isPathAllowed('/etc/passwd')).toBe(true);
      expect(isPathAllowed('/any/path')).toBe(true);
    });

    it('should allow all paths when DATA_DIR is set but ALLOWED_ROOT_DIRECTORY is not', async () => {
      process.env.DATA_DIR = '/data';
      delete process.env.ALLOWED_ROOT_DIRECTORY;

      const { initAllowedPaths, isPathAllowed } = await import('@automaker/platform');
      initAllowedPaths();

      // DATA_DIR should be allowed
      expect(isPathAllowed('/data/settings.json')).toBe(true);
      // But all other paths should also be allowed when ALLOWED_ROOT_DIRECTORY is not set
      expect(isPathAllowed('/allowed/project/file.txt')).toBe(true);
      expect(isPathAllowed('/not/allowed/file.txt')).toBe(true);
      expect(isPathAllowed('/tmp/file.txt')).toBe(true);
      expect(isPathAllowed('/etc/passwd')).toBe(true);
      expect(isPathAllowed('/any/path')).toBe(true);
    });
  });

  describe('validatePath', () => {
    it('should return resolved path for allowed paths', async () => {
      process.env.ALLOWED_ROOT_DIRECTORY = '/allowed';
      process.env.DATA_DIR = '';

      const { initAllowedPaths, validatePath } = await import('@automaker/platform');
      initAllowedPaths();

      const result = validatePath('/allowed/file.txt');
      expect(result).toBe(path.resolve('/allowed/file.txt'));
    });

    it('should throw error for paths outside allowed directories', async () => {
      process.env.ALLOWED_ROOT_DIRECTORY = '/allowed';
      process.env.DATA_DIR = '';

      const { initAllowedPaths, validatePath } = await import('@automaker/platform');
      initAllowedPaths();

      // Disallowed paths should throw PathNotAllowedError
      expect(() => validatePath('/disallowed/file.txt')).toThrow();
    });

    it('should not throw error for any path when no restrictions are configured', async () => {
      delete process.env.DATA_DIR;
      delete process.env.ALLOWED_ROOT_DIRECTORY;

      const { initAllowedPaths, validatePath } = await import('@automaker/platform');
      initAllowedPaths();

      // All paths are allowed when no restrictions configured
      expect(() => validatePath('/disallowed/file.txt')).not.toThrow();
      expect(validatePath('/disallowed/file.txt')).toBe(path.resolve('/disallowed/file.txt'));
    });

    it('should resolve relative paths within allowed directory', async () => {
      const cwd = process.cwd();
      process.env.ALLOWED_ROOT_DIRECTORY = cwd;
      process.env.DATA_DIR = '';

      const { initAllowedPaths, validatePath } = await import('@automaker/platform');
      initAllowedPaths();

      const result = validatePath('./file.txt');
      expect(result).toBe(path.resolve(cwd, './file.txt'));
    });
  });

  describe('getAllowedPaths', () => {
    it('should return array of allowed paths', async () => {
      process.env.ALLOWED_ROOT_DIRECTORY = '/projects';
      process.env.DATA_DIR = '/data';

      const { initAllowedPaths, getAllowedPaths } = await import('@automaker/platform');
      initAllowedPaths();

      const result = getAllowedPaths();
      expect(Array.isArray(result)).toBe(true);
      expect(result.length).toBe(2);
      expect(result).toContain(path.resolve('/projects'));
      expect(result).toContain(path.resolve('/data'));
    });

    it('should return resolved paths', async () => {
      process.env.ALLOWED_ROOT_DIRECTORY = '/test';
      process.env.DATA_DIR = '';

      const { initAllowedPaths, getAllowedPaths } = await import('@automaker/platform');
      initAllowedPaths();

      const result = getAllowedPaths();
      expect(result[0]).toBe(path.resolve('/test'));
    });
  });
});
