import { describe, expect, it } from 'vitest'
import {
  buildRenderedTemplateRequest,
  buildTemplateVariables,
  extractTemplateError,
  readJsonPath,
  renderTemplateString,
  renderTemplateValue,
  resolveTemplateEndpointUrl,
} from '@/lib/openai-compat-template-runtime'

describe('model-gateway openai-compat template renderer', () => {
  it('renders placeholders in strings and nested body values', () => {
    const variables = buildTemplateVariables({
      model: 'veo3.1',
      prompt: 'a cat running',
      image: 'https://a.test/cat.png',
      taskId: 'task_1',
    })

    expect(renderTemplateString('/videos/{{task_id}}', variables)).toBe('/videos/task_1')
    expect(renderTemplateValue({
      model: '{{model}}',
      prompt: '{{prompt}}',
      images: '{{images}}',
      nested: [{ value: '{{task_id}}' }],
    }, variables)).toEqual({
      model: 'veo3.1',
      prompt: 'a cat running',
      images: [],
      nested: [{ value: 'task_1' }],
    })
  })

  it('resolves relative path against base url and injects auth header', async () => {
    const request = await buildRenderedTemplateRequest({
      baseUrl: 'https://compat.example.com/v1/',
      endpoint: {
        method: 'POST',
        path: '/v2/videos/generations',
        contentType: 'application/json',
        bodyTemplate: {
          model: '{{model}}',
          prompt: '{{prompt}}',
        },
      },
      variables: buildTemplateVariables({
        model: 'veo3.1',
        prompt: 'hello',
      }),
      defaultAuthHeader: 'Bearer sk-test',
    })

    expect(resolveTemplateEndpointUrl('https://compat.example.com/v1/', '/v2/videos/generations'))
      .toBe('https://compat.example.com/v1/v2/videos/generations')
    expect(request.endpointUrl).toBe('https://compat.example.com/v1/v2/videos/generations')
    expect(request.headers.Authorization).toBe('Bearer sk-test')
    expect(request.headers['Content-Type']).toBe('application/json')
    expect(request.body).toBe(JSON.stringify({
      model: 'veo3.1',
      prompt: 'hello',
    }))
  })

  it('deduplicates /v1 prefix when base url already ends with /v1', async () => {
    const request = await buildRenderedTemplateRequest({
      baseUrl: 'https://yunwu.ai/v1',
      endpoint: {
        method: 'GET',
        path: '/v1/video/query?id={{task_id}}',
      },
      variables: buildTemplateVariables({
        model: 'veo_3_1-fast-4K',
        prompt: '',
        taskId: 'task_abc',
      }),
      defaultAuthHeader: 'Bearer sk-test',
    })

    expect(resolveTemplateEndpointUrl('https://yunwu.ai/v1', '/v1/video/create'))
      .toBe('https://yunwu.ai/v1/video/create')
    expect(request.endpointUrl).toBe('https://yunwu.ai/v1/video/query?id=task_abc')
    expect(request.headers.Authorization).toBe('Bearer sk-test')
  })

  it('builds multipart form data and omits explicit content-type header', async () => {
    const dataUrl = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO0p6s8AAAAASUVORK5CYII='
    const request = await buildRenderedTemplateRequest({
      baseUrl: 'https://compat.example.com/v1',
      endpoint: {
        method: 'POST',
        path: '/videos',
        contentType: 'multipart/form-data',
        multipartFileFields: ['input_reference'],
        bodyTemplate: {
          model: '{{model}}',
          prompt: '{{prompt}}',
          input_reference: '{{image}}',
        },
      },
      variables: buildTemplateVariables({
        model: 'veo3.1',
        prompt: 'hello',
        image: dataUrl,
      }),
      defaultAuthHeader: 'Bearer sk-test',
    })

    expect(request.endpointUrl).toBe('https://compat.example.com/v1/videos')
    expect(request.headers.Authorization).toBe('Bearer sk-test')
    expect(request.headers['Content-Type']).toBeUndefined()
    expect(request.body).toBeInstanceOf(FormData)

    const formData = request.body as FormData
    expect(formData.get('model')).toBe('veo3.1')
    expect(formData.get('prompt')).toBe('hello')
    const fileValue = formData.get('input_reference')
    expect(fileValue).toBeInstanceOf(File)
    expect((fileValue as File).name).toBe('reference-0.png')
  })

  it('builds application/x-www-form-urlencoded bodies', async () => {
    const request = await buildRenderedTemplateRequest({
      baseUrl: 'https://compat.example.com/v1',
      endpoint: {
        method: 'POST',
        path: '/videos/query',
        contentType: 'application/x-www-form-urlencoded',
        bodyTemplate: {
          model: '{{model}}',
          task_id: '{{task_id}}',
        },
      },
      variables: buildTemplateVariables({
        model: 'veo3.1',
        prompt: 'hello',
        taskId: 'task_1',
      }),
    })

    expect(request.headers['Content-Type']).toBe('application/x-www-form-urlencoded')
    expect(request.body).toBeInstanceOf(URLSearchParams)
    expect((request.body as URLSearchParams).toString()).toBe('model=veo3.1&task_id=task_1')
  })

  it('reads json path for array/object outputs', () => {
    const payload = {
      data: [{ url: 'https://cdn.test/1.png' }],
      task: {
        status: 'succeeded',
      },
    }
    expect(readJsonPath(payload, '$.data[0].url')).toBe('https://cdn.test/1.png')
    expect(readJsonPath(payload, '$.task.status')).toBe('succeeded')
  })

  it('extracts upstream error message from common payload shape', () => {
    const message = extractTemplateError({
      version: 1,
      mediaType: 'video',
      mode: 'async',
      create: {
        method: 'POST',
        path: '/video/create',
      },
      status: {
        method: 'GET',
        path: '/video/query?id={{task_id}}',
      },
      response: {
        taskIdPath: '$.id',
        statusPath: '$.status',
      },
      polling: {
        intervalMs: 5000,
        timeoutMs: 600000,
        doneStates: ['completed'],
        failStates: ['failed'],
      },
    }, {
      error: {
        message_zh: '当前分组上游负载已饱和，请稍后再试',
      },
    }, 500)

    expect(message).toContain('status 500')
    expect(message).toContain('当前分组上游负载已饱和，请稍后再试')
  })
})
