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

import { fetchTag, fetchTagByName, fetchTags } from '@/lib/tags'

import type { FetchTagsParams } from '@/types'

const api = vi.hoisted (() => ({
  apiGet: vi.fn (),
}))

vi.mock ('@/lib/api', () => api)

const baseParams: FetchTagsParams = {
  post:         null,
  name:         '',
  category:     null,
  postCountGTE: 0,
  postCountLTE: null,
  createdFrom:  '',
  createdTo:    '',
  updatedFrom:  '',
  updatedTo:    '',
  deprecated:   null,
  page:         1,
  limit:        30,
  order:        'updated_at:desc',
}

describe ('tags API functions', () => {
  beforeEach (() => {
    vi.clearAllMocks ()
  })

  it ('maps tag filters to backend parameters', async () => {
    api.apiGet.mockResolvedValueOnce ({ tags: [], count: 0 })

    await fetchTags ({
      ...baseParams,
      name:         '虹',
      category:     'character',
      postCountGTE: 10,
      postCountLTE: 20,
    })

    expect (api.apiGet).toHaveBeenCalledWith (
        '/tags',
        {
          params: {
            name:           '虹',
            category:       'character',
            post_count_gte: 10,
            post_count_lte: 20,
            page:           1,
            limit:          30,
            order:          'updated_at:desc',
          },
        },
    )
  })

  it.each ([
    [true, '1'],
    [false, '0'],
  ] as const) ('maps deprecated=%s to %s', async (deprecated, expected) => {
    api.apiGet.mockResolvedValueOnce ({ tags: [], count: 0 })

    await fetchTags ({ ...baseParams, deprecated })

    expect (api.apiGet).toHaveBeenCalledWith (
        '/tags',
        { params: expect.objectContaining ({ deprecated: expected }) },
    )
  })

  it ('returns null when tag fetches fail', async () => {
    api.apiGet.mockRejectedValueOnce (new Error ('missing'))
    api.apiGet.mockRejectedValueOnce (new Error ('missing'))

    await expect (fetchTag ('1')).resolves.toBeNull ()
    await expect (fetchTagByName ('unknown')).resolves.toBeNull ()
  })
})
