import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import LoadMoreButton from '@/components/article/LoadMoreButton'

process.env.NEXT_PUBLIC_DIRECTUS_URL = 'https://cms.achmad.dev'
process.env.NEXT_PUBLIC_DIRECTUS_TOKEN = 'test-token'

const mockFetch = vi.fn()
global.fetch = mockFetch

beforeEach(() => {
  vi.resetAllMocks()
  mockFetch.mockResolvedValue({
    json: () => Promise.resolve({ data: [] }),
  })
})

describe('LoadMoreButton', () => {
  it('renders the Load more button by default', () => {
    render(<LoadMoreButton categorySlug="games" initialCount={12} />)
    expect(screen.getByText('Load more')).toBeInTheDocument()
  })

  it('hides the button when hasMore is false', () => {
    render(<LoadMoreButton categorySlug="games" initialCount={12} hasMore={false} />)
    expect(screen.queryByText('Load more')).not.toBeInTheDocument()
  })

  it('shows loading state while fetching', async () => {
    mockFetch.mockImplementation(
      () =>
        new Promise((resolve) =>
          setTimeout(
            () =>
              resolve({
                json: () => Promise.resolve({ data: [] }),
              }),
            100,
          ),
        ),
    )

    render(<LoadMoreButton categorySlug="games" initialCount={12} />)
    fireEvent.click(screen.getByText('Load more'))

    expect(await screen.findByText('Loading…')).toBeInTheDocument()
  })

  it('fetches articles with correct parameters', async () => {
    render(<LoadMoreButton categorySlug="games" initialCount={12} />)
    fireEvent.click(screen.getByText('Load more'))

    await waitFor(() => {
      expect(mockFetch).toHaveBeenCalledTimes(1)
    })

    const url = mockFetch.mock.calls[0][0] as string
    expect(url).toContain('/items/articles')
    expect(url).toContain('games')
    expect(url).toContain('offset=12')
    expect(url).toContain('limit=12')
    expect(url).toContain('access_token=test-token')
  })

  it('appends fetched articles to the display', async () => {
    mockFetch.mockResolvedValue({
      json: () =>
        Promise.resolve({
          data: [
            {
              id: '101',
              title: 'Loaded Article',
              slug: 'loaded-article',
              excerpt: null,
              featured_image: null,
              published_at: null,
              date_created: '2026-05-31T00:00:00Z',
              is_featured: false,
              category: { id: '1', name: 'Games', slug: 'games' },
            },
          ],
        }),
    })

    render(<LoadMoreButton categorySlug="games" initialCount={12} />)
    fireEvent.click(screen.getByText('Load more'))

    await waitFor(() => {
      expect(screen.getByText('Loaded Article')).toBeInTheDocument()
    })
  })

  it('hides button after last page when fewer results than limit are returned', async () => {
    mockFetch.mockResolvedValue({
      json: () => Promise.resolve({ data: [] }),
    })

    render(<LoadMoreButton categorySlug="games" initialCount={12} />)
    expect(screen.getByText('Load more')).toBeInTheDocument()

    fireEvent.click(screen.getByText('Load more'))

    await waitFor(() => {
      expect(screen.queryByText('Load more')).not.toBeInTheDocument()
    })
  })

  it('keeps button visible when exactly limit articles are returned', async () => {
    const articles = Array.from({ length: 12 }, (_, i) => ({
      id: String(200 + i),
      title: `Article ${i}`,
      slug: `article-${i}`,
      excerpt: null,
      featured_image: null,
      published_at: null,
      date_created: '2026-05-31T00:00:00Z',
      is_featured: false,
      category: { id: '1', name: 'Games', slug: 'games' },
    }))

    mockFetch.mockResolvedValue({
      json: () => Promise.resolve({ data: articles }),
    })

    render(<LoadMoreButton categorySlug="games" initialCount={12} />)
    fireEvent.click(screen.getByText('Load more'))

    await waitFor(() => {
      expect(screen.getByText('Load more')).toBeInTheDocument()
    })
  })

  it('calls the correct Directus API URL', async () => {
    render(<LoadMoreButton categorySlug="vtubers" initialCount={14} />)
    fireEvent.click(screen.getByText('Load more'))

    await waitFor(() => {
      expect(mockFetch).toHaveBeenCalledTimes(1)
    })

    const url = mockFetch.mock.calls[0][0] as string
    expect(url).toContain('vtubers')
    expect(url).toContain('offset=14')
  })
})
