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

// Mock fs
vi.mock('fs', () => ({
  existsSync: vi.fn(),
  readFileSync: vi.fn(),
  writeFileSync: vi.fn(),
  mkdirSync: vi.fn(),
}));

// Mock provider registry
vi.mock('../../../src/provider/index.js', () => ({
  providerRegistry: {
    getInfo: vi.fn(),
    getConfig: vi.fn(),
  },
  resolveApiKey: vi.fn(),
}));

import * as fs from 'fs';
import { providerRegistry, resolveApiKey } from '../../../src/provider/index.js';
import { getConfig, loadConfig, saveConfig, loadVisionConfig } from '../../../src/utils/config.js';

describe('Config - 配置管理', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('getConfig - 获取原始配置', () => {
    it('配置文件存在时返回内容', () => {
      vi.mocked(fs.existsSync).mockReturnValue(true);
      vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({
        provider: 'anthropic',
        model: 'claude-3-opus',
      }));

      const config = getConfig();

      expect(config.provider).toBe('anthropic');
      expect(config.model).toBe('claude-3-opus');
    });

    it('配置文件不存在时返回空对象', () => {
      vi.mocked(fs.existsSync).mockReturnValue(false);

      const config = getConfig();

      expect(config).toEqual({});
    });

    it('配置文件解析错误时返回空对象', () => {
      vi.mocked(fs.existsSync).mockReturnValue(true);
      vi.mocked(fs.readFileSync).mockReturnValue('invalid json');

      const config = getConfig();

      expect(config).toEqual({});
    });
  });

  describe('loadConfig - 加载完整配置', () => {
    it('通过 ProviderRegistry 获取 Anthropic 配置', () => {
      vi.mocked(fs.existsSync).mockReturnValue(false);
      vi.mocked(providerRegistry.getConfig).mockReturnValue(undefined);
      vi.mocked(resolveApiKey).mockReturnValue('resolved-anthropic-key');

      const config = loadConfig();

      expect(config.provider).toBe('anthropic');
      expect(config.apiKey).toBe('resolved-anthropic-key');
      expect(config.model).toBe('claude-sonnet-4-20250514');
    });

    it('从配置文件获取 DeepSeek provider', () => {
      vi.mocked(fs.existsSync).mockReturnValue(true);
      vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({
        provider: 'deepseek',
      }));
      vi.mocked(providerRegistry.getConfig).mockReturnValue(undefined);
      vi.mocked(resolveApiKey).mockReturnValue('resolved-deepseek-key');

      const config = loadConfig();

      expect(config.provider).toBe('deepseek');
      expect(config.apiKey).toBe('resolved-deepseek-key');
      expect(config.model).toBe('deepseek-chat');
    });

    it('配置文件中的 model 和 maxTokens', () => {
      vi.mocked(fs.existsSync).mockReturnValue(true);
      vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({
        model: 'custom-model',
        maxTokens: 8192,
      }));
      vi.mocked(providerRegistry.getConfig).mockReturnValue(undefined);
      vi.mocked(resolveApiKey).mockReturnValue('test-key');

      const config = loadConfig();

      expect(config.model).toBe('custom-model');
      expect(config.maxTokens).toBe(8192);
    });

    it('包含系统提示词', () => {
      vi.mocked(fs.existsSync).mockReturnValue(false);
      vi.mocked(resolveApiKey).mockReturnValue('test-key');

      const config = loadConfig();

      expect(config.systemPrompt).toBeDefined();
      expect(config.systemPrompt).toContain('终端');
    });

    it('默认 maxTokens 为 4096', () => {
      vi.mocked(fs.existsSync).mockReturnValue(false);
      vi.mocked(resolveApiKey).mockReturnValue('test-key');

      const config = loadConfig();

      expect(config.maxTokens).toBe(4096);
    });

    it('从配置文件获取 baseUrl', () => {
      vi.mocked(fs.existsSync).mockReturnValue(true);
      vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({
        baseUrl: 'https://custom.api.com/v1',
      }));
      vi.mocked(resolveApiKey).mockReturnValue('test-key');

      const config = loadConfig();

      expect(config.baseUrl).toBe('https://custom.api.com/v1');
    });

    it('从 ProviderConfig 获取 baseUrl', () => {
      vi.mocked(fs.existsSync).mockReturnValue(false);
      vi.mocked(providerRegistry.getConfig).mockReturnValue({
        id: 'anthropic',
        baseUrl: 'https://provider-config.api.com/v1',
      });
      vi.mocked(resolveApiKey).mockReturnValue('test-key');

      const config = loadConfig();

      expect(config.baseUrl).toBe('https://provider-config.api.com/v1');
    });
  });

  describe('saveConfig - 保存配置', () => {
    it('创建目录并保存配置', () => {
      vi.mocked(fs.existsSync).mockReturnValue(false);

      saveConfig({ provider: 'anthropic' });

      expect(fs.mkdirSync).toHaveBeenCalledWith(
        expect.any(String),
        { recursive: true }
      );
      expect(fs.writeFileSync).toHaveBeenCalledWith(
        expect.any(String),
        expect.stringContaining('anthropic')
      );
    });

    it('合并现有配置', () => {
      vi.mocked(fs.existsSync).mockReturnValue(true);
      vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({
        provider: 'anthropic',
        model: 'old-model',
      }));

      saveConfig({ model: 'new-model' });

      const writeCall = vi.mocked(fs.writeFileSync).mock.calls[0];
      const savedConfig = JSON.parse(writeCall[1] as string);

      expect(savedConfig.provider).toBe('anthropic');
      expect(savedConfig.model).toBe('new-model');
    });

    it('目录已存在时不重新创建', () => {
      vi.mocked(fs.existsSync)
        .mockReturnValueOnce(true)  // 目录存在
        .mockReturnValueOnce(true); // 配置文件存在
      vi.mocked(fs.readFileSync).mockReturnValue('{}');

      saveConfig({ provider: 'test' });

      expect(fs.mkdirSync).not.toHaveBeenCalled();
    });
  });

  describe('loadVisionConfig - Vision 配置', () => {
    it('返回 null 当没有配置 Vision API Key', () => {
      vi.mocked(fs.existsSync).mockReturnValue(false);
      vi.mocked(resolveApiKey).mockReturnValue(undefined);

      const visionConfig = loadVisionConfig();

      expect(visionConfig).toBeNull();
    });

    it('通过 ProviderRegistry 获取 Vision 配置', () => {
      vi.mocked(fs.existsSync).mockReturnValue(true);
      vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({
        visionProvider: 'openai',
        visionModel: 'gpt-4-vision',
      }));
      vi.mocked(resolveApiKey).mockReturnValue('vision-api-key');

      const visionConfig = loadVisionConfig();

      expect(visionConfig).not.toBeNull();
      expect(visionConfig?.provider).toBe('openai');
      expect(visionConfig?.apiKey).toBe('vision-api-key');
      expect(visionConfig?.model).toBe('gpt-4-vision');
    });

    it('默认使用 anthropic provider', () => {
      vi.mocked(fs.existsSync).mockReturnValue(false);
      vi.mocked(resolveApiKey).mockReturnValue('anthropic-key');

      const visionConfig = loadVisionConfig();

      expect(visionConfig).not.toBeNull();
      expect(visionConfig?.provider).toBe('anthropic');
    });

    it('Vision baseUrl 配置', () => {
      vi.mocked(fs.existsSync).mockReturnValue(true);
      vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({
        visionBaseUrl: 'https://vision.api.com/v1',
      }));
      vi.mocked(resolveApiKey).mockReturnValue('vision-key');

      const visionConfig = loadVisionConfig();

      expect(visionConfig?.baseUrl).toBe('https://vision.api.com/v1');
    });

    it('使用默认 Vision 模型', () => {
      vi.mocked(fs.existsSync).mockReturnValue(false);
      vi.mocked(resolveApiKey).mockReturnValue('test-key');

      const visionConfig = loadVisionConfig();

      expect(visionConfig?.model).toBe('claude-sonnet-4-20250514');
    });
  });
});
