import React from 'react'
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import TagInput from './TagInput'
import { getMaxUserTags } from '../../config/tags'

const MAX_TAGS = getMaxUserTags()

function tagsAtLimitMinus(remaining) {
  return Array.from({ length: MAX_TAGS - remaining }, (_, index) => `t${index + 1}`)
}

function tagsAtLimit() {
  return Array.from({ length: MAX_TAGS }, (_, index) => `a${index + 1}`)
}

function Harness({ initial = [] }) {
  const [tags, setTags] = React.useState(initial)

  return (
    <TagInput
      value={tags}
      onChange={setTags}
      suggestedTags={['sunset', 'city']}
      searchEndpoint="/api/tags/search"
      popularEndpoint="/api/tags/popular"
    />
  )
}

describe('TagInput', () => {
  beforeEach(() => {
    window.axios = {
      get: vi.fn(async (url) => {
        if (url.startsWith('/api/tags/search')) {
          return {
            data: {
              data: [
                { id: 1, name: 'cityscape', slug: 'cityscape', usage_count: 10, recent_clicks: 2 },
                { id: 2, name: 'city', slug: 'city', usage_count: 30, recent_clicks: 14 },
              ],
            },
          }
        }

        return {
          data: {
            data: [
              { id: 3, name: 'popular', slug: 'popular', usage_count: 99 },
            ],
          },
        }
      }),
    }
  })

  afterEach(() => {
    vi.restoreAllMocks()
  })

  it('adds and removes tags', async () => {
    render(<Harness />)

    const input = screen.getByLabelText('Tag input')
    await userEvent.type(input, 'night,')

    expect(screen.getByText('night')).not.toBeNull()

    await userEvent.click(screen.getByRole('button', { name: 'Remove tag night' }))
    expect(screen.queryByText('night')).toBeNull()
  })

  it('supports keyboard suggestion accept with tab', async () => {
    render(<Harness />)

    const input = screen.getByLabelText('Tag input')
    await userEvent.type(input, 'city')

    await waitFor(() => {
      expect(screen.getAllByRole('option').length).toBeGreaterThan(0)
    })

    await userEvent.keyboard('{Tab}')
    expect(screen.getByRole('button', { name: /Remove tag/i })).not.toBeNull()
  })

  it('shows recent click momentum when suggestions provide it', async () => {
    render(<Harness />)

    const input = screen.getByLabelText('Tag input')
    await userEvent.type(input, 'city')

    await waitFor(() => {
      expect(screen.getByText('14 recent')).not.toBeNull()
    })
  })

  it('shows a confirmation dialog before adding comma-separated pasted tags', async () => {
    render(<Harness />)

    const input = screen.getByLabelText('Tag input')
    await userEvent.click(input)
    await userEvent.paste('art, city, night')

    expect(screen.getByRole('dialog')).not.toBeNull()
    expect(screen.queryByRole('button', { name: 'Remove tag art' })).toBeNull()

    await userEvent.click(screen.getByRole('button', { name: 'Add tags' }))

    expect(screen.getByRole('button', { name: 'Remove tag art' })).not.toBeNull()
    expect(screen.getByRole('button', { name: 'Remove tag city' })).not.toBeNull()
    expect(screen.getByRole('button', { name: 'Remove tag night' })).not.toBeNull()
  })

  it('warns when pasted tags exceed the max and only adds the allowed tags', async () => {
    render(<Harness initial={tagsAtLimitMinus(1)} />)

    const input = screen.getByLabelText('Tag input')
    await userEvent.click(input)
    await userEvent.paste('alpha, beta, gamma')

    expect(screen.getByText(`Only 1 tag can be added because the limit is ${MAX_TAGS}. 2 pasted tags will be skipped.`)).not.toBeNull()

    await userEvent.click(screen.getByRole('button', { name: 'Add tags' }))

    expect(screen.getByRole('button', { name: 'Remove tag alpha' })).not.toBeNull()
    expect(screen.queryByRole('button', { name: 'Remove tag beta' })).toBeNull()
    expect(screen.queryByRole('button', { name: 'Remove tag gamma' })).toBeNull()
  })

  it('handles API failure gracefully', async () => {
    window.axios.get = vi.fn(async () => {
      throw new Error('network')
    })

    render(<Harness />)

    const input = screen.getByLabelText('Tag input')
    await userEvent.type(input, 'cyber')

    await waitFor(() => {
      expect(screen.getByText('Tag search unavailable')).not.toBeNull()
    })
  })

  it('enforces max tags limit', async () => {
    render(<Harness initial={tagsAtLimit()} />)

    const input = screen.getByLabelText('Tag input')
    await userEvent.type(input, 'overflow{enter}')

    expect(screen.getByText('Max tags reached')).not.toBeNull()
    expect(screen.queryByText('overflow')).toBeNull()
  })
})
