/**
 * Providers Route 测试
 *
 * 测试模型提供商管理 REST API 端点
 */

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

// Use vi.hoisted to create mocks
const mockRegistry = vi.hoisted(() => ({
  listForApi: vi.fn(),
  getDetail: vi.fn(),
  getModels: vi.fn(),
  has: vi.fn(),
  testConnection: vi.fn(),
  registerCustom: vi.fn(),
  setConfig: vi.fn(),
  saveConfig: vi.fn(),
  removeCustom: vi.fn(),
  addCustomModel: vi.fn(),
  removeCustomModel: vi.fn(),
}));

const mockCoreModule = vi.hoisted(() => ({
  getProviderRegistry: vi.fn(() => mockRegistry),
}));

// Track if core module should be available
let coreModuleAvailable = true;

vi.mock('@ai-assistant/core', () => {
  if (!coreModuleAvailable) {
    throw new Error('Module not found');
  }
  return mockCoreModule;
});

import { providersRouter } from '../../../src/routes/providers.js';

// Create test app
const app = new Hono();
app.route('/providers', providersRouter);

describe('Providers Route', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    coreModuleAvailable = true;
  });

  describe('GET /providers - 列出所有提供商', () => {
    it('返回提供商列表', async () => {
      const providers = [
        { id: 'anthropic', name: 'Anthropic', builtin: true, enabled: true, hasApiKey: true, modelCount: 5 },
        { id: 'openai', name: 'OpenAI', builtin: true, enabled: false, hasApiKey: false, modelCount: 10 },
      ];
      mockRegistry.listForApi.mockReturnValue(providers);

      const res = await app.request('/providers');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data).toEqual(providers);
    });

    it('返回空列表', async () => {
      mockRegistry.listForApi.mockReturnValue([]);

      const res = await app.request('/providers');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.data).toEqual([]);
    });
  });

  describe('GET /providers/:id - 获取提供商详情', () => {
    it('返回提供商详情', async () => {
      const detail = {
        id: 'anthropic',
        name: 'Anthropic',
        builtin: true,
        models: [{ id: 'claude-3', name: 'Claude 3' }],
        config: { enabled: true, hasApiKey: true },
      };
      mockRegistry.getDetail.mockReturnValue(detail);

      const res = await app.request('/providers/anthropic');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data).toEqual(detail);
    });

    it('提供商不存在返回 404', async () => {
      mockRegistry.getDetail.mockReturnValue(undefined);

      const res = await app.request('/providers/non-existent');
      const json = await res.json();

      expect(res.status).toBe(404);
      expect(json.success).toBe(false);
      expect(json.error).toContain('not found');
    });
  });

  describe('GET /providers/:id/models - 获取模型列表', () => {
    it('返回模型列表', async () => {
      const models = [
        { id: 'claude-3-opus', name: 'Claude 3 Opus', contextWindow: 200000 },
        { id: 'claude-3-sonnet', name: 'Claude 3 Sonnet', contextWindow: 200000 },
      ];
      mockRegistry.has.mockReturnValue(true);
      mockRegistry.getModels.mockReturnValue(models);

      const res = await app.request('/providers/anthropic/models');
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data).toEqual(models);
    });

    it('提供商不存在返回 404', async () => {
      mockRegistry.has.mockReturnValue(false);

      const res = await app.request('/providers/non-existent/models');
      const json = await res.json();

      expect(res.status).toBe(404);
      expect(json.success).toBe(false);
    });
  });

  describe('POST /providers/:id/test - 测试连接', () => {
    it('测试连接成功', async () => {
      mockRegistry.testConnection.mockResolvedValue({
        success: true,
        latency: 150,
      });

      const res = await app.request('/providers/anthropic/test', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ apiKey: 'test-key' }),
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(json.data.success).toBe(true);
      expect(json.data.latency).toBe(150);
    });

    it('测试连接失败', async () => {
      mockRegistry.testConnection.mockResolvedValue({
        success: false,
        error: 'Invalid API key',
      });

      const res = await app.request('/providers/anthropic/test', {
        method: 'POST',
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.data.success).toBe(false);
      expect(json.data.error).toBe('Invalid API key');
    });
  });

  describe('POST /providers - 注册自定义提供商', () => {
    it('注册成功', async () => {
      mockRegistry.registerCustom.mockReturnValue(undefined);
      mockRegistry.saveConfig.mockResolvedValue(undefined);

      const res = await app.request('/providers', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          id: 'custom-provider',
          name: 'Custom Provider',
          baseUrl: 'https://api.custom.com',
        }),
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(mockRegistry.registerCustom).toHaveBeenCalled();
      expect(mockRegistry.saveConfig).toHaveBeenCalled();
    });

    it('缺少必需字段返回 400', async () => {
      const res = await app.request('/providers', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ id: 'custom' }),
      });
      const json = await res.json();

      expect(res.status).toBe(400);
      expect(json.success).toBe(false);
      expect(json.error).toContain('Missing required fields');
    });
  });

  describe('PUT /providers/:id - 更新配置', () => {
    it('更新成功', async () => {
      mockRegistry.has.mockReturnValue(true);
      mockRegistry.setConfig.mockReturnValue(undefined);
      mockRegistry.saveConfig.mockResolvedValue(undefined);

      const res = await app.request('/providers/anthropic', {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ enabled: true, apiKey: 'new-key' }),
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(mockRegistry.setConfig).toHaveBeenCalled();
    });

    it('提供商不存在返回 404', async () => {
      mockRegistry.has.mockReturnValue(false);

      const res = await app.request('/providers/non-existent', {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ enabled: true }),
      });
      const json = await res.json();

      expect(res.status).toBe(404);
      expect(json.success).toBe(false);
    });
  });

  describe('DELETE /providers/:id - 删除自定义提供商', () => {
    it('删除成功', async () => {
      mockRegistry.removeCustom.mockReturnValue(true);
      mockRegistry.saveConfig.mockResolvedValue(undefined);

      const res = await app.request('/providers/custom-provider', {
        method: 'DELETE',
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
    });

    it('提供商不存在返回 404', async () => {
      mockRegistry.removeCustom.mockReturnValue(false);

      const res = await app.request('/providers/non-existent', {
        method: 'DELETE',
      });
      const json = await res.json();

      expect(res.status).toBe(404);
      expect(json.success).toBe(false);
    });
  });

  describe('POST /providers/:id/models - 添加自定义模型', () => {
    it('添加成功', async () => {
      mockRegistry.addCustomModel.mockReturnValue(undefined);
      mockRegistry.saveConfig.mockResolvedValue(undefined);

      const res = await app.request('/providers/anthropic/models', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          id: 'custom-model',
          name: 'Custom Model',
          contextWindow: 100000,
        }),
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
      expect(mockRegistry.addCustomModel).toHaveBeenCalledWith('anthropic', expect.any(Object));
    });

    it('缺少必需字段返回 400', async () => {
      const res = await app.request('/providers/anthropic/models', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ id: 'model' }),
      });
      const json = await res.json();

      expect(res.status).toBe(400);
      expect(json.error).toContain('Missing required fields');
    });
  });

  describe('DELETE /providers/:id/models/:modelId - 删除自定义模型', () => {
    it('删除成功', async () => {
      mockRegistry.removeCustomModel.mockReturnValue(true);
      mockRegistry.saveConfig.mockResolvedValue(undefined);

      const res = await app.request('/providers/anthropic/models/custom-model', {
        method: 'DELETE',
      });
      const json = await res.json();

      expect(res.status).toBe(200);
      expect(json.success).toBe(true);
    });

    it('模型不存在返回 404', async () => {
      mockRegistry.removeCustomModel.mockReturnValue(false);

      const res = await app.request('/providers/anthropic/models/non-existent', {
        method: 'DELETE',
      });
      const json = await res.json();

      expect(res.status).toBe(404);
      expect(json.success).toBe(false);
    });
  });
});
