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

import { fetchPostChanges, fetchPosts, toggleViewedFlg, updatePost } from '@/lib/posts'

import type { FetchPostsParams } from '@/types'

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

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

const baseParams: FetchPostsParams = {
  url:                 '',
  title:               '',
  tags:                '',
  match:               'all',
  originalCreatedFrom: '',
  originalCreatedTo:   '',
  createdFrom:         '',
  createdTo:           '',
  updatedFrom:         '',
  updatedTo:           '',
  page:                1,
  limit:               20,
  order:               'updated_at:desc',
}

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

  it ('maps post search parameters to backend snake_case names', async () => {
    api.apiGet.mockResolvedValueOnce ({ posts: [], count: 0 })

    await fetchPosts ({
      ...baseParams,
      title:               'title',
      tags:                'a b',
      originalCreatedFrom: '2026-01-01',
      updatedTo:           '2026-02-01',
    })

    expect (api.apiGet).toHaveBeenCalledWith (
        '/posts',
        {
          params: {
            title:                 'title',
            tags:                  'a b',
            match:                 'all',
            original_created_from: '2026-01-01',
            updated_to:            '2026-02-01',
            page:                  1,
            limit:                 20,
            order:                 'updated_at:desc',
          },
        },
    )
  })

  it ('updates posts with version and merge controls', async () => {
    api.apiPut.mockResolvedValueOnce ({ id: 5 })

    await updatePost (
        {
          id:                    5,
          title:                 'new title',
          tags:                  'tag',
          duration:              null,
          parentPostIds:         '1 2',
          originalCreatedFrom:   null,
          originalCreatedBefore: '2026-01-02T00:00:00Z',
        },
        { baseVersionNo: 7, force: true, merge: false },
    )

    expect (api.apiPut).toHaveBeenCalledWith (
        '/posts/5',
        {
          title:                   'new title',
          tags:                    'tag',
          duration:                null,
          parent_post_ids:         '1 2',
          original_created_from:   null,
          original_created_before: '2026-01-02T00:00:00Z',
        },
        {
          params: {
            base_version_no: '7',
            force:           '1',
            merge:           '0',
          },
        },
    )
  })

  it ('uses the viewed endpoint method matching the requested state', async () => {
    await toggleViewedFlg ('9', true)
    await toggleViewedFlg ('9', false)

    expect (api.apiPost).toHaveBeenCalledWith ('/posts/9/viewed')
    expect (api.apiDelete).toHaveBeenCalledWith ('/posts/9/viewed')
  })

  it ('keeps optional post history filters out when blank', async () => {
    api.apiGet.mockResolvedValueOnce ({ versions: [], count: 0 })

    await fetchPostChanges ({ page: 2, limit: 50 })

    expect (api.apiGet).toHaveBeenCalledWith (
        '/posts/versions',
        { params: { page: 2, limit: 50 } },
    )
  })
})
