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

const mockProviders: Provider[] = [
  {
    id: 'openai',
    name: 'OpenAI',
    apiKey: 'sk-test',
    baseUrl: 'https://api.openai.com/v1',
    protocol: 'openai',
    enabled: true,
    createdAt: '2024-01-01T00:00:00Z',
    updatedAt: '2024-01-01T00:00:00Z',
  },
  {
    id: 'anthropic',
    name: 'Anthropic',
    apiKey: 'sk-ant-test',
    baseUrl: 'https://api.anthropic.com',
    protocol: 'anthropic',
    enabled: true,
    createdAt: '2024-01-02T00:00:00Z',
    updatedAt: '2024-01-02T00:00:00Z',
  },
]

const mockModel: Model = {
  id: 'gpt-4o',
  providerId: 'openai',
  modelName: 'gpt-4o',
  enabled: true,
  createdAt: '2024-01-01T00:00:00Z',
  unifiedId: 'openai/gpt-4o',
}

const defaultProps = {
  open: true,
  providerId: 'openai',
  providers: mockProviders,
  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('ModelForm', () => {
  it('renders form with provider select', () => {
    render(<ModelForm {...defaultProps} />)

    const dialog = getDialog()
    expect(within(dialog).getByText('添加模型')).toBeInTheDocument()
    expect(within(dialog).getByText('供应商')).toBeInTheDocument()
    expect(within(dialog).getByText('模型名称')).toBeInTheDocument()
    expect(within(dialog).getByText('启用')).toBeInTheDocument()
  })

  it('defaults providerId to the passed providerId in create mode', () => {
    render(<ModelForm {...defaultProps} />)

    const dialog = getDialog()
    // Form renders with provider select
    expect(within(dialog).getByText('供应商')).toBeInTheDocument()
  })

  it('shows validation error messages for required fields', async () => {
    const user = userEvent.setup()
    render(<ModelForm {...defaultProps} providerId={undefined as unknown as string} providers={[]} />)

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

    expect(await screen.findByText('请选择供应商')).toBeInTheDocument()
    expect(screen.getByText('请输入模型名称')).toBeInTheDocument()
  })

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

    const dialog = getDialog()
    // Only one input with placeholder "例如: gpt-4o" for model name
    const modelNameInput = within(dialog).getByPlaceholderText('例如: gpt-4o')

    // Type into the model name field
    await user.clear(modelNameInput)
    await user.type(modelNameInput, 'gpt-4o-mini')

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

    // Wait for the onSave to be called
    await vi.waitFor(() => {
      expect(onSave).toHaveBeenCalledWith(
        expect.objectContaining({
          providerId: 'openai',
          modelName: 'gpt-4o-mini',
          enabled: true,
        })
      )
    })
  }, 10000)

  it('renders pre-filled fields in edit mode', () => {
    render(<ModelForm {...defaultProps} model={mockModel} />)

    const dialog = getDialog()
    expect(within(dialog).getByText('编辑模型')).toBeInTheDocument()

    // Check model name input
    const modelNameInput = within(dialog).getByPlaceholderText('例如: gpt-4o') as HTMLInputElement
    expect(modelNameInput.value).toBe('gpt-4o')
  })

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

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