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

const openAIState = vi.hoisted(() => ({
  create: vi.fn(),
  toFile: vi.fn(async () => ({ name: 'reference-file' })),
}))

const getProviderConfigMock = vi.hoisted(() => vi.fn(async () => ({
  id: 'openai-compatible:oa-1',
  apiKey: 'oa-key',
  baseUrl: 'https://oa.test/v1',
})))

const normalizeToBase64ForGenerationMock = vi.hoisted(() => vi.fn(async () => 'data:image/png;base64,QQ=='))

vi.mock('openai', () => ({
  default: class OpenAI {
    videos = {
      create: openAIState.create,
    }
  },
  toFile: openAIState.toFile,
}))

vi.mock('@/lib/api-config', () => ({
  getProviderConfig: getProviderConfigMock,
}))

vi.mock('@/lib/media/outbound-image', () => ({
  normalizeToBase64ForGeneration: normalizeToBase64ForGenerationMock,
}))

import { OpenAICompatibleVideoGenerator } from '@/lib/generators/video/openai-compatible'

describe('OpenAICompatibleVideoGenerator', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    getProviderConfigMock.mockResolvedValue({
      id: 'openai-compatible:oa-1',
      apiKey: 'oa-key',
      baseUrl: 'https://oa.test/v1',
    })
  })

  it('submits official videos.create payload and returns OPENAI externalId', async () => {
    openAIState.create.mockResolvedValueOnce({ id: 'vid_123' })

    const generator = new OpenAICompatibleVideoGenerator('openai-compatible:oa-1')
    const result = await generator.generate({
      userId: 'user-1',
      imageUrl: 'https://example.com/seed.png',
      prompt: 'animate this character',
      options: {
        modelId: 'sora-2',
        duration: 8,
        resolution: '720p',
        aspectRatio: '16:9',
      },
    })

    expect(result.success).toBe(true)
    expect(result.async).toBe(true)
    expect(result.requestId).toBe('vid_123')

    const expectedProviderToken = Buffer.from('openai-compatible:oa-1', 'utf8').toString('base64url')
    expect(result.externalId).toBe(`OPENAI:VIDEO:${expectedProviderToken}:vid_123`)

    const createCall = openAIState.create.mock.calls[0]
    expect(createCall).toBeTruthy()
    if (!createCall) {
      throw new Error('videos.create should be called')
    }

    expect(createCall[0]).toMatchObject({
      prompt: 'animate this character',
      model: 'sora-2',
      seconds: '8',
      size: '1280x720',
    })
    expect((createCall[0] as { input_reference?: unknown }).input_reference).toBeDefined()
  })

  it('allows custom model ids for openai-compatible gateways', async () => {
    openAIState.create.mockResolvedValueOnce({ id: 'vid_custom' })

    const generator = new OpenAICompatibleVideoGenerator('openai-compatible:oa-1')
    const result = await generator.generate({
      userId: 'user-1',
      imageUrl: 'https://example.com/seed.png',
      prompt: 'animate',
      options: {
        modelId: 'veo_3_1-fast-4K',
      },
    })

    expect(result.success).toBe(true)
    const createCall = openAIState.create.mock.calls.at(0)
    expect(createCall).toBeTruthy()
    if (!createCall) {
      throw new Error('videos.create should be called')
    }
    expect((createCall[0] as { model?: string }).model).toBe('veo_3_1-fast-4K')
  })

  it('maps 3:2 to landscape size explicitly', async () => {
    openAIState.create.mockResolvedValueOnce({ id: 'vid_32' })

    const generator = new OpenAICompatibleVideoGenerator('openai-compatible:oa-1')
    const result = await generator.generate({
      userId: 'user-1',
      imageUrl: 'https://example.com/seed.png',
      prompt: 'animate',
      options: {
        resolution: '1080p',
        aspectRatio: '3:2',
      },
    })

    expect(result.success).toBe(true)
    const createCall = openAIState.create.mock.calls.at(0)
    expect(createCall).toBeTruthy()
    if (!createCall) {
      throw new Error('videos.create should be called')
    }
    expect((createCall[0] as { size?: string }).size).toBe('1792x1024')
  })

  it('maps 2:3 to portrait size explicitly', async () => {
    openAIState.create.mockResolvedValueOnce({ id: 'vid_23' })

    const generator = new OpenAICompatibleVideoGenerator('openai-compatible:oa-1')
    const result = await generator.generate({
      userId: 'user-1',
      imageUrl: 'https://example.com/seed.png',
      prompt: 'animate',
      options: {
        resolution: '720p',
        aspectRatio: '2:3',
      },
    })

    expect(result.success).toBe(true)
    const createCall = openAIState.create.mock.calls.at(0)
    expect(createCall).toBeTruthy()
    if (!createCall) {
      throw new Error('videos.create should be called')
    }
    expect((createCall[0] as { size?: string }).size).toBe('720x1280')
  })

  it('fails explicitly on unsupported aspect ratios', async () => {
    const generator = new OpenAICompatibleVideoGenerator('openai-compatible:oa-1')
    const result = await generator.generate({
      userId: 'user-1',
      imageUrl: 'https://example.com/seed.png',
      prompt: 'animate',
      options: {
        resolution: '720p',
        aspectRatio: '5:4',
      },
    })

    expect(result.success).toBe(false)
    expect(result.error).toContain('OPENAI_COMPAT_VIDEO_ASPECT_RATIO_UNSUPPORTED')
  })
})
