import { render, screen, within, fireEvent } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { describe, it, expect, vi } from 'vitest'
import { ProviderForm } from '@/pages/Providers/ProviderForm'
import type { Provider } from '@/types'

const mockProvider: Provider = {
  id: 'openai',
  name: 'OpenAI',
  apiKey: 'sk-old-key',
  baseUrl: 'https://api.openai.com/v1',
  protocol: 'openai',
  enabled: true,
  createdAt: '2024-01-01T00:00:00Z',
  updatedAt: '2024-01-01T00:00:00Z',
}

const defaultProps = {
  open: true,
  onSave: vi.fn(),
  onCancel: vi.fn(),
  loading: false,
}

function getDialog() {
  // TDesign Dialog doesn't have role="dialog", use class selector
  const dialog = document.querySelector('.t-dialog')
  if (!dialog) {
    throw new Error('Dialog not found')
  }
  return dialog
}

describe('ProviderForm', () => {
  it('renders form fields in create mode', () => {
    render(<ProviderForm {...defaultProps} />)

    const dialog = getDialog()
    expect(within(dialog).getByText('添加供应商')).toBeInTheDocument()
    expect(within(dialog).getByText('ID')).toBeInTheDocument()
    expect(within(dialog).getByText('名称')).toBeInTheDocument()
    expect(within(dialog).getByText('API Key')).toBeInTheDocument()
    expect(within(dialog).getByText('Base URL')).toBeInTheDocument()
    expect(within(dialog).getByText('协议')).toBeInTheDocument()
    expect(within(dialog).getByText('启用')).toBeInTheDocument()
    expect(within(dialog).getByPlaceholderText('例如: openai')).toBeInTheDocument()
    expect(within(dialog).getByPlaceholderText('例如: OpenAI')).toBeInTheDocument()
    expect(within(dialog).getByPlaceholderText('例如: https://api.openai.com/v1')).toBeInTheDocument()
  })

  it('renders pre-filled fields in edit mode', () => {
    render(<ProviderForm {...defaultProps} provider={mockProvider} />)

    const dialog = getDialog()
    expect(within(dialog).getByText('编辑供应商')).toBeInTheDocument()

    const idInput = within(dialog).getByPlaceholderText('例如: openai') as HTMLInputElement
    expect(idInput.value).toBe('openai')
    expect(idInput).toBeDisabled()

    const nameInput = within(dialog).getByPlaceholderText('例如: OpenAI') as HTMLInputElement
    expect(nameInput.value).toBe('OpenAI')

    const baseUrlInput = within(dialog).getByPlaceholderText('例如: https://api.openai.com/v1') as HTMLInputElement
    expect(baseUrlInput.value).toBe('https://api.openai.com/v1')

    const apiKeyInput = within(dialog).getByPlaceholderText('sk-...') as HTMLInputElement
    expect(apiKeyInput.value).toBe('sk-old-key')
  })

  it('shows API Key label in edit mode', () => {
    render(<ProviderForm {...defaultProps} provider={mockProvider} />)

    const dialog = getDialog()
    expect(within(dialog).getByText('API Key')).toBeInTheDocument()
  })

  it('shows validation error messages for required fields', async () => {
    const user = userEvent.setup()
    render(<ProviderForm {...defaultProps} />)

    const dialog = getDialog()
    const okButton = within(dialog).getByRole('button', { name: /保/ })
    await user.click(okButton)

    // Wait for validation messages to appear
    expect(await screen.findByText('请输入供应商 ID')).toBeInTheDocument()
    expect(screen.getByText('请输入名称')).toBeInTheDocument()
    expect(screen.getByText('请输入 API Key')).toBeInTheDocument()
    expect(screen.getByText('请输入 Base URL')).toBeInTheDocument()
  })

  it('calls onSave with form values on successful submission', async () => {
    const onSave = vi.fn()
    render(<ProviderForm {...defaultProps} onSave={onSave} />)

    const dialog = getDialog()

    // Get form instance and set values directly
    const idInput = within(dialog).getByPlaceholderText('例如: openai') as HTMLInputElement
    const nameInput = within(dialog).getByPlaceholderText('例如: OpenAI') as HTMLInputElement
    const apiKeyInput = within(dialog).getByPlaceholderText('sk-...') as HTMLInputElement
    const baseUrlInput = within(dialog).getByPlaceholderText('例如: https://api.openai.com/v1') as HTMLInputElement

    // Simulate user input by directly setting values
    fireEvent.change(idInput, { target: { value: 'test-provider' } })
    fireEvent.change(nameInput, { target: { value: 'Test Provider' } })
    fireEvent.change(apiKeyInput, { target: { value: 'sk-test-key' } })
    fireEvent.change(baseUrlInput, { target: { value: 'https://api.test.com/v1' } })

    const okButton = within(dialog).getByRole('button', { name: /保/ })
    fireEvent.click(okButton)

    // Wait for the onSave to be called
    await vi.waitFor(
      () => {
        expect(onSave).toHaveBeenCalled()
      },
      { timeout: 5000 }
    )
  }, 10000)

  it('calls onCancel when clicking cancel button', async () => {
    const user = userEvent.setup()
    const onCancel = vi.fn()
    render(<ProviderForm {...defaultProps} onCancel={onCancel} />)

    const dialog = getDialog()
    const cancelButton = within(dialog).getByRole('button', { name: /取/ })
    await user.click(cancelButton)
    expect(onCancel).toHaveBeenCalledTimes(1)
  })

  it('shows confirm loading state', () => {
    render(<ProviderForm {...defaultProps} loading={true} />)
    const dialog = getDialog()
    const okButton = within(dialog).getByRole('button', { name: /保/ })
    // TDesign uses t-is-loading class for loading state
    expect(okButton).toHaveClass('t-is-loading')
  })

  it('shows validation error for invalid URL format', async () => {
    const user = userEvent.setup()
    render(<ProviderForm {...defaultProps} />)

    const dialog = getDialog()

    // Fill in required fields
    await user.type(within(dialog).getByPlaceholderText('例如: openai'), 'test-provider')
    await user.type(within(dialog).getByPlaceholderText('例如: OpenAI'), 'Test Provider')
    await user.type(within(dialog).getByPlaceholderText('sk-...'), 'sk-test-key')

    // Enter an invalid URL in the Base URL field
    await user.type(within(dialog).getByPlaceholderText('例如: https://api.openai.com/v1'), 'not-a-url')

    // Submit the form
    const okButton = within(dialog).getByRole('button', { name: /保/ })
    await user.click(okButton)

    // Verify that a URL validation error message appears
    await vi.waitFor(() => {
      expect(screen.getByText('请输入有效的 URL')).toBeInTheDocument()
    })
  }, 15000)

  it('renders protocol select field with default value', () => {
    render(<ProviderForm {...defaultProps} />)

    const dialog = getDialog()
    expect(within(dialog).getByText('协议')).toBeInTheDocument()
  })

  it('includes protocol field in form submission', async () => {
    const onSave = vi.fn()
    render(<ProviderForm {...defaultProps} onSave={onSave} />)

    const dialog = getDialog()

    // Get form instance and set values directly
    const idInput = within(dialog).getByPlaceholderText('例如: openai') as HTMLInputElement
    const nameInput = within(dialog).getByPlaceholderText('例如: OpenAI') as HTMLInputElement
    const apiKeyInput = within(dialog).getByPlaceholderText('sk-...') as HTMLInputElement
    const baseUrlInput = within(dialog).getByPlaceholderText('例如: https://api.openai.com/v1') as HTMLInputElement

    // Simulate user input by directly setting values
    fireEvent.change(idInput, { target: { value: 'test-provider' } })
    fireEvent.change(nameInput, { target: { value: 'Test Provider' } })
    fireEvent.change(apiKeyInput, { target: { value: 'sk-test-key' } })
    fireEvent.change(baseUrlInput, { target: { value: 'https://api.test.com/v1' } })

    const okButton = within(dialog).getByRole('button', { name: /保/ })
    fireEvent.click(okButton)

    // Wait for the onSave to be called
    await vi.waitFor(
      () => {
        expect(onSave).toHaveBeenCalled()
        // Verify that the saved data includes a protocol field
        const savedData = onSave.mock.calls[0][0]
        expect(savedData).toHaveProperty('protocol')
      },
      { timeout: 5000 }
    )
  }, 10000)
})
