import { describe, it, expect, afterEach } from 'vitest';
import { loadConfigSafe, redactSecrets, getConfigPath, getDataDir } from './shared.js';
import { writeFileSync, mkdirSync, rmSync } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';

describe('CLI shared utilities', () => {
  const testDir = join(tmpdir(), 'flynn-test-cli-shared');

  afterEach(() => {
    try { rmSync(testDir, { recursive: true }); } catch {}
  });

  describe('getConfigPath', () => {
    it('returns FLYNN_CONFIG env var if set', () => {
      const original = process.env.FLYNN_CONFIG;
      process.env.FLYNN_CONFIG = '/custom/path.yaml';
      expect(getConfigPath()).toBe('/custom/path.yaml');
      if (original !== undefined) {
        process.env.FLYNN_CONFIG = original;
      } else {
        delete process.env.FLYNN_CONFIG;
      }
    });

    it('returns default path if env var not set', () => {
      const original = process.env.FLYNN_CONFIG;
      delete process.env.FLYNN_CONFIG;
      const path = getConfigPath();
      expect(path).toContain('.config/flynn/config.yaml');
      if (original !== undefined) {
        process.env.FLYNN_CONFIG = original;
      }
    });
  });

  describe('loadConfigSafe', () => {
    it('returns config on success', () => {
      mkdirSync(testDir, { recursive: true });
      const configPath = join(testDir, 'config.yaml');
      writeFileSync(configPath, `
telegram:
  bot_token: "test-token"
  allowed_chat_ids: [123]
models:
  default:
    provider: anthropic
    model: claude-sonnet
`);
      const result = loadConfigSafe(configPath);
      expect(result.config).toBeDefined();
      expect(result.error).toBeUndefined();
      expect(result.config!.telegram?.bot_token).toBe('test-token');
    });

    it('loads env vars from FLYNN_ENV_FILE before parsing config', () => {
      const prevEnvFile = process.env.FLYNN_ENV_FILE;
      const prevToken = process.env.TEST_BOT_TOKEN;
      delete process.env.TEST_BOT_TOKEN;

      mkdirSync(testDir, { recursive: true });
      const envPath = join(testDir, 'cloud.env');
      const configPath = join(testDir, 'config.yaml');

      writeFileSync(envPath, 'TEST_BOT_TOKEN=test-token\n');
      process.env.FLYNN_ENV_FILE = envPath;

      writeFileSync(configPath, `
telegram:
  bot_token: \${TEST_BOT_TOKEN}
  allowed_chat_ids: [123]
models:
  default:
    provider: anthropic
    model: claude-sonnet
`);

      const result = loadConfigSafe(configPath);
      expect(result.config).toBeDefined();
      expect(result.error).toBeUndefined();
      expect(result.config!.telegram?.bot_token).toBe('test-token');

      if (prevEnvFile !== undefined) {
        process.env.FLYNN_ENV_FILE = prevEnvFile;
      } else {
        delete process.env.FLYNN_ENV_FILE;
      }
      if (prevToken !== undefined) {
        process.env.TEST_BOT_TOKEN = prevToken;
      } else {
        delete process.env.TEST_BOT_TOKEN;
      }
    });

    it('returns error when file not found', () => {
      const result = loadConfigSafe('/nonexistent/config.yaml');
      expect(result.config).toBeUndefined();
      expect(result.error).toBeDefined();
    });

    it('returns error on invalid YAML', () => {
      mkdirSync(testDir, { recursive: true });
      const configPath = join(testDir, 'bad.yaml');
      writeFileSync(configPath, '{{{{invalid yaml');
      const result = loadConfigSafe(configPath);
      expect(result.config).toBeUndefined();
      expect(result.error).toBeDefined();
    });
  });

  describe('redactSecrets', () => {
    it('redacts bot_token', () => {
      const config = {
        telegram: { bot_token: 'secret-token-123', allowed_chat_ids: [123] },
        models: { default: { provider: 'anthropic', model: 'claude' } },
      };
      const redacted = redactSecrets(config);
      const telegram = redacted.telegram as Record<string, unknown>;
      expect(telegram.bot_token).toBe('***');
      expect(telegram.allowed_chat_ids).toEqual([123]);
    });

    it('redacts api_key in models', () => {
      const config = {
        telegram: { bot_token: 'token', allowed_chat_ids: [123] },
        models: {
          default: { provider: 'anthropic', model: 'claude', api_key: 'sk-secret' },
        },
      };
      const redacted = redactSecrets(config);
      const models = redacted.models as Record<string, Record<string, unknown>>;
      expect(models.default.api_key).toBe('***');
    });

    it('redacts access_token (matrix)', () => {
      const config = {
        matrix: { homeserver_url: 'https://matrix.example.org', access_token: 'mx-secret' },
        models: { default: { provider: 'anthropic', model: 'claude' } },
      };
      const redacted = redactSecrets(config);
      const matrix = redacted.matrix as Record<string, unknown>;
      expect(matrix.access_token).toBe('***');
    });
  });

  describe('getDataDir', () => {
    it('returns path under home directory', () => {
      const dir = getDataDir();
      expect(dir).toContain('.local/share/flynn');
    });
  });
});
