/**
 * (download certificate / Postman collection mutations).
 */
import React from 'react'
import { renderHook, waitFor } from '@testing-library/react'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { toast } from 'sonner'

import {
  useDownloadCertificate,
  useDownloadPostmanCollectionMutation,
} from '../scenario.mutations'

const mockGetScenarioPostmanCollection = jest.fn()
const mockGenerateScenarioCertificate = jest.fn()
const mockDownloadJsonFile = jest.fn()
const mockDownloadBlobFile = jest.fn()
const mockGetAxiosErrorMessageAsync = jest.fn()

jest.mock('../scenario.service', () => ({
  __esModule: true,
  default: {
    getScenarioPostmanCollection: (...args: unknown[]) =>
      mockGetScenarioPostmanCollection(...args),
    generateScenarioCertificate: (...args: unknown[]) =>
      mockGenerateScenarioCertificate(...args),
  },
}))

jest.mock('@/util/download', () => ({
  downloadJsonFile: (...args: unknown[]) => mockDownloadJsonFile(...args),
  downloadBlobFile: (...args: unknown[]) => mockDownloadBlobFile(...args),
}))

jest.mock('@/util/axios-error-message', () => ({
  getAxiosErrorMessageAsync: (...args: unknown[]) =>
    mockGetAxiosErrorMessageAsync(...args),
}))

jest.mock('next-intl', () => ({
  useTranslations: () => (key: string) => key,
}))

jest.mock('sonner', () => ({
  toast: {
    dismiss: jest.fn(),
    error: jest.fn(),
    loading: jest.fn(),
  },
}))

const postmanPayload = {
  info: {
    name: 'c',
    description: '',
    schema:
      'https://schema.getpostman.com/json/collection/v2.1.0/collection.json',
  },
  variable: [],
  auth: { type: 'bearer', bearer: [] },
  item: [],
}

function createWrapper() {
  const client = new QueryClient({
    defaultOptions: { mutations: { retry: false } },
  })
  return function Wrapper({ children }: { children: React.ReactNode }) {
    return <QueryClientProvider client={client}>{children}</QueryClientProvider>
  }
}

describe('[services/scenario] scenario.mutations', () => {
  beforeEach(() => {
    mockGetScenarioPostmanCollection.mockReset()
    mockGenerateScenarioCertificate.mockReset()
    mockDownloadJsonFile.mockReset()
    mockDownloadBlobFile.mockReset()
    mockGetAxiosErrorMessageAsync.mockReset()
  })

  it('useDownloadPostmanCollectionMutation gọi API và downloadJsonFile khi success', async () => {
    mockGetScenarioPostmanCollection.mockResolvedValue({
      message: 'OK',
      code: '200',
      data: postmanPayload,
    })

    const { result } = renderHook(
      () =>
        useDownloadPostmanCollectionMutation(
          'sc-1',
          'case-1',
          'v-1',
          'api-1',
          'MyCase',
        ),
      { wrapper: createWrapper() },
    )

    result.current.mutate()

    await waitFor(() => expect(result.current.isSuccess).toBe(true))

    expect(mockGetScenarioPostmanCollection).toHaveBeenCalledWith(
      'sc-1',
      'case-1',
      'v-1',
      'api-1',
    )
    expect(mockDownloadJsonFile).toHaveBeenCalledTimes(1)
    expect(mockDownloadJsonFile).toHaveBeenCalledWith(
      postmanPayload,
      'MyCase.postman_collection.json',
    )
  })

  it('shows translated fallback message when API error has no server message', async () => {
    mockGetScenarioPostmanCollection.mockRejectedValueOnce(new Error('network'))
    const { result } = renderHook(
      () =>
        useDownloadPostmanCollectionMutation(
          'sc-1',
          'case-1',
          'v-1',
          'api-1',
          'MyCase'
        ),
      { wrapper: createWrapper() }
    )

    result.current.mutate()
    await waitFor(() => expect(result.current.isError).toBe(true))

    expect(toast.dismiss).toHaveBeenCalled()
    expect(toast.error).toHaveBeenCalledWith(
      'mess.download_postman_collection.error'
    )
  })

  it('useDownloadCertificate gọi API và downloadBlobFile khi success', async () => {
    const blob = new Blob(['pdf-content'], { type: 'application/pdf' })
    mockGenerateScenarioCertificate.mockResolvedValueOnce(blob)

    const { result } = renderHook(() => useDownloadCertificate('cert-1'), {
      wrapper: createWrapper(),
    })

    result.current.mutate()
    await waitFor(() => expect(result.current.isSuccess).toBe(true))

    expect(toast.dismiss).toHaveBeenCalled()
    expect(toast.loading).toHaveBeenCalledWith('mess.download.loading')
    expect(mockGenerateScenarioCertificate).toHaveBeenCalledWith('cert-1')
    expect(mockDownloadBlobFile).toHaveBeenCalledWith(blob, 'certificate.pdf')
  })

  it('useDownloadCertificate parse lỗi blob/json rồi hiện toast', async () => {
    const apiError = { response: { data: new Blob(['x']) } }
    mockGenerateScenarioCertificate.mockRejectedValueOnce(apiError)
    mockGetAxiosErrorMessageAsync.mockResolvedValueOnce('blob-error')

    const { result } = renderHook(() => useDownloadCertificate('cert-2'), {
      wrapper: createWrapper(),
    })

    result.current.mutate()
    await waitFor(() => expect(result.current.isError).toBe(true))

    expect(mockGetAxiosErrorMessageAsync).toHaveBeenCalledWith(
      apiError,
      'mess.download.error'
    )
    expect(toast.error).toHaveBeenCalledWith('blob-error')
  })
})
