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

function createJsonResponse(body: unknown) {
  return new Response(JSON.stringify(body), {
    status: 200,
    headers: { 'content-type': 'application/json' },
  })
}

function buildRequest() {
  return {
    model: 'test-model',
    maxTokens: 321,
    temperature: 0.4,
    messages: [
      { role: 'system' as const, content: 'Follow policy' },
      { role: 'user' as const, content: 'Summarize this invoice' },
      { role: 'assistant' as const, content: 'Previous answer' },
      { role: 'user' as const, content: 'Try again briefly' },
    ],
  }
}

describe('ai platform parity', () => {
  beforeEach(() => {
    vi.resetModules()
    vi.clearAllMocks()
  })

  it('matches anthropic request payloads on call()', async () => {
    const [{ AnthropicAdapter }, { getAiAdapter }] = await Promise.all([
      import('../../../../../../packages/ai/src/adapters/anthropic'),
      import('../ai'),
    ])

    const platformFetch = vi.fn().mockResolvedValue(
      createJsonResponse({
        model: 'test-model',
        content: [{ type: 'text', text: 'ok' }],
        stop_reason: 'end_turn',
        usage: { input_tokens: 10, output_tokens: 4 },
      }),
    )

    const hostAdapter = new AnthropicAdapter({
      ANTHROPIC_API_KEY: 'anthropic-key',
      OPENAI_API_KEY: 'openai-key',
      GOOGLE_AI_API_KEY: 'google-key',
    })
    const anthropicCreate = vi.fn().mockResolvedValue({
      content: [{ type: 'text', text: 'ok' }],
      usage: { input_tokens: 10, output_tokens: 4 },
    })
    ;(hostAdapter as unknown as { client: { messages: { create: typeof anthropicCreate } } }).client = {
      messages: { create: anthropicCreate },
    }
    const platformAdapter = getAiAdapter(
      {
        ANTHROPIC_API_KEY: 'anthropic-key',
        OPENAI_API_KEY: 'openai-key',
        GOOGLE_AI_API_KEY: 'google-key',
      },
      'anthropic',
      {
        anthropicFetch: platformFetch,
      },
    )

    const request = buildRequest()
    await hostAdapter.call(request)
    await platformAdapter.call(request)

    const hostPayload = anthropicCreate.mock.calls[0]?.[0]
    const platformPayload = JSON.parse(platformFetch.mock.calls[0]?.[1]?.body as string)

    expect(platformPayload).toEqual(hostPayload)
  })

  it('matches openai request payloads on call()', async () => {
    const [{ OpenAIAdapter }, { getAiAdapter }] = await Promise.all([
      import('../../../../../../packages/ai/src/adapters/openai'),
      import('../ai'),
    ])

    const platformFetch = vi.fn().mockResolvedValue(
      createJsonResponse({
        model: 'test-model',
        choices: [{ message: { content: 'ok' }, finish_reason: 'stop' }],
        usage: { prompt_tokens: 10, completion_tokens: 4 },
      }),
    )

    const hostAdapter = new OpenAIAdapter({
      ANTHROPIC_API_KEY: 'anthropic-key',
      OPENAI_API_KEY: 'openai-key',
      GOOGLE_AI_API_KEY: 'google-key',
    })
    const openAiCreate = vi.fn().mockResolvedValue({
      choices: [{ message: { content: 'ok' } }],
      usage: { prompt_tokens: 10, completion_tokens: 4 },
    })
    ;(hostAdapter as unknown as { client: { chat: { completions: { create: typeof openAiCreate } } } }).client = {
      chat: { completions: { create: openAiCreate } },
    }
    const platformAdapter = getAiAdapter(
      {
        ANTHROPIC_API_KEY: 'anthropic-key',
        OPENAI_API_KEY: 'openai-key',
        GOOGLE_AI_API_KEY: 'google-key',
      },
      'openai',
      {
        openAiFetch: platformFetch,
      },
    )

    const request = buildRequest()
    await hostAdapter.call(request)
    await platformAdapter.call(request)

    const hostPayload = openAiCreate.mock.calls[0]?.[0]
    const platformPayload = JSON.parse(platformFetch.mock.calls[0]?.[1]?.body as string)

    expect(platformPayload).toEqual(hostPayload)
  })

  it('matches google request semantics on call()', async () => {
    const [{ GoogleAdapter }, { getAiAdapter }] = await Promise.all([
      import('../../../../../../packages/ai/src/adapters/google'),
      import('../ai'),
    ])

    const generateContent = vi.fn().mockResolvedValue({
      text: 'ok',
      usageMetadata: { promptTokenCount: 10, candidatesTokenCount: 4 },
    })
    const googleGetGenerativeModel = vi.fn()
    const googleStartChat = vi.fn()
    const googleSendMessage = vi.fn().mockResolvedValue({
      response: {
        text: () => 'ok',
        usageMetadata: { promptTokenCount: 10, candidatesTokenCount: 4 },
      },
    })
    googleStartChat.mockReturnValue({ sendMessage: googleSendMessage })
    googleGetGenerativeModel.mockReturnValue({ startChat: googleStartChat })

    const hostAdapter = new GoogleAdapter({
      ANTHROPIC_API_KEY: 'anthropic-key',
      OPENAI_API_KEY: 'openai-key',
      GOOGLE_AI_API_KEY: 'google-key',
    })
    ;(hostAdapter as unknown as { genAI: { getGenerativeModel: typeof googleGetGenerativeModel } }).genAI = {
      getGenerativeModel: googleGetGenerativeModel,
    }
    const platformAdapter = getAiAdapter(
      {
        ANTHROPIC_API_KEY: 'anthropic-key',
        OPENAI_API_KEY: 'openai-key',
        GOOGLE_AI_API_KEY: 'google-key',
      },
      'google',
      {
        createGoogleClient: () => ({
          models: { generateContent },
        }),
      },
    )

    const request = buildRequest()
    await hostAdapter.call(request)
    await platformAdapter.call(request)

    const hostModelConfig = googleGetGenerativeModel.mock.calls[0]?.[0]
    const hostHistory = googleStartChat.mock.calls[0]?.[0]?.history
    const hostMessage = googleSendMessage.mock.calls[0]?.[0]
    const platformPayload = generateContent.mock.calls[0]?.[0]

    expect(platformPayload).toEqual({
      model: hostModelConfig.model,
      config: {
        systemInstruction: hostModelConfig.systemInstruction,
        maxOutputTokens: hostModelConfig.generationConfig.maxOutputTokens,
        temperature: hostModelConfig.generationConfig.temperature,
      },
      contents: [...hostHistory, { role: 'user', parts: hostMessage }],
    })
  })
})
