import type { Features } from '../../../types'
import type { OnFeaturesChange } from '@/app/components/base/features/types'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { TtsAutoPlay } from '@/types/app'
import { FeaturesProvider } from '../../../context'
import ParamConfigContent from '../param-config-content'

let mockLanguages = [
  { value: 'en-US', name: 'English', example: 'Hello world' },
  { value: 'zh-Hans', name: '中文', example: '你好' },
]

let mockPathname = '/app/test-app-id/configuration'

let mockVoiceItems: { value: string, name: string }[] | undefined = [
  { value: 'alloy', name: 'Alloy' },
  { value: 'echo', name: 'Echo' },
]

const mockUseAppVoices = vi.fn((_appId: string, _language?: string) => ({
  data: mockVoiceItems,
}))

vi.mock('@/next/navigation', () => ({
  usePathname: () => mockPathname,
  useParams: () => ({}),
}))

vi.mock('@/i18n-config/language', () => ({
  get languages() {
    return mockLanguages
  },
}))

vi.mock('@/service/use-apps', () => ({
  useAppVoices: (appId: string, language?: string) => mockUseAppVoices(appId, language),
}))

const defaultFeatures: Features = {
  moreLikeThis: { enabled: false },
  opening: { enabled: false },
  suggested: { enabled: false },
  text2speech: { enabled: true, language: 'en-US', voice: 'alloy', autoPlay: TtsAutoPlay.disabled },
  speech2text: { enabled: false },
  citation: { enabled: false },
  moderation: { enabled: false },
  file: { enabled: false },
  annotationReply: { enabled: false },
}

const renderWithProvider = (
  props: { onClose?: () => void, onChange?: OnFeaturesChange } = {},
  featureOverrides?: Partial<Features>,
) => {
  const features = { ...defaultFeatures, ...featureOverrides }
  return render(
    <FeaturesProvider features={features}>
      <ParamConfigContent
        onClose={props.onClose ?? vi.fn()}
        onChange={props.onChange}
      />
    </FeaturesProvider>,
  )
}

const getLanguageSelect = () => screen.getByRole('combobox', { name: /voice\.voiceSettings\.language/ })
const getVoiceSelect = () => screen.getByRole('combobox', { name: /voice\.voiceSettings\.voice/ })

describe('ParamConfigContent', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    mockPathname = '/app/test-app-id/configuration'
    mockLanguages = [
      { value: 'en-US', name: 'English', example: 'Hello world' },
      { value: 'zh-Hans', name: '中文', example: '你好' },
    ]
    mockVoiceItems = [
      { value: 'alloy', name: 'Alloy' },
      { value: 'echo', name: 'Echo' },
    ]
  })

  // Rendering states and static UI sections.
  describe('Rendering', () => {
    it('should render voice settings title', () => {
      renderWithProvider()

      expect(screen.getByText(/voice\.voiceSettings\.title/))!.toBeInTheDocument()
    })

    it('should render language label', () => {
      renderWithProvider()

      expect(screen.getByText(/voice\.voiceSettings\.language/))!.toBeInTheDocument()
    })

    it('should render voice label', () => {
      renderWithProvider()

      expect(screen.getByText(/voice\.voiceSettings\.voice/))!.toBeInTheDocument()
    })

    it('should render autoPlay toggle', () => {
      renderWithProvider()

      expect(screen.getByText(/voice\.voiceSettings\.autoPlay/))!.toBeInTheDocument()
      expect(screen.getByRole('switch'))!.toBeInTheDocument()
    })

    it('should render tooltip icon for language', () => {
      renderWithProvider()

      const languageLabel = screen.getByText(/voice\.voiceSettings\.language/)
      expect(languageLabel)!.toBeInTheDocument()
      expect(screen.getByRole('button', { name: /voice\.voiceSettings\.resolutionTooltip/ }))!.toBeInTheDocument()
    })

    it('should display language listbox button', () => {
      renderWithProvider()

      expect(getLanguageSelect()).toBeInTheDocument()
    })

    it('should display current voice in listbox button', () => {
      renderWithProvider()

      expect(getVoiceSelect()).toHaveTextContent('Alloy')
    })

    it('should render audition button when language has example', () => {
      renderWithProvider()

      const auditionButton = screen.queryByRole('group', { name: /appApi\.play|play/i })
      expect(auditionButton)!.toBeInTheDocument()
    })

    it('should not render audition button when language has no example', () => {
      mockLanguages = [
        { value: 'en-US', name: 'English', example: '' },
        { value: 'zh-Hans', name: '中文', example: '' },
      ]

      renderWithProvider()

      const auditionButton = screen.queryByRole('group', { name: /appApi\.play|play/i })
      expect(auditionButton).toBeNull()
    })

    it('should render with no language set and use first as default', () => {
      renderWithProvider({}, {
        text2speech: { enabled: true, language: '', voice: '', autoPlay: TtsAutoPlay.disabled },
      })

      expect(getLanguageSelect()).toBeInTheDocument()
    })

    it('should render with no voice set and use first as default', () => {
      renderWithProvider({}, {
        text2speech: { enabled: true, language: 'en-US', voice: 'nonexistent', autoPlay: TtsAutoPlay.disabled },
      })

      expect(getVoiceSelect()).toHaveTextContent('Alloy')
    })
  })

  // User-triggered behavior and callbacks.
  describe('User Interactions', () => {
    it('should call onClose when close button is clicked', async () => {
      const onClose = vi.fn()
      renderWithProvider({ onClose })

      const closeButton = screen.getByRole('button', { name: /close/i })
      await userEvent.click(closeButton)

      expect(onClose).toHaveBeenCalled()
    })

    it('should call onClose when close button receives Enter key', async () => {
      const onClose = vi.fn()
      renderWithProvider({ onClose })

      const closeButton = screen.getByRole('button', { name: /close/i })
      await userEvent.click(closeButton)
      onClose.mockClear()
      closeButton.focus()
      await userEvent.keyboard('{Enter}')

      expect(onClose).toHaveBeenCalled()
    })

    it('should not call onClose when close button receives unrelated key', async () => {
      const onClose = vi.fn()
      renderWithProvider({ onClose })

      const closeButton = screen.getByRole('button', { name: /close/i })
      closeButton.focus()
      await userEvent.keyboard('{Escape}')

      expect(onClose).not.toHaveBeenCalled()
    })

    it('should toggle autoPlay switch and call onChange', async () => {
      const onChange = vi.fn()
      renderWithProvider({ onChange })

      await userEvent.click(screen.getByRole('switch'))

      expect(onChange).toHaveBeenCalled()
    })

    it('should set autoPlay to disabled when toggled off from enabled state', async () => {
      const onChange = vi.fn()
      renderWithProvider(
        { onChange },
        { text2speech: { enabled: true, language: 'en-US', voice: 'alloy', autoPlay: TtsAutoPlay.enabled } },
      )

      const autoPlaySwitch = screen.getByRole('switch')
      expect(autoPlaySwitch)!.toHaveAttribute('aria-checked', 'true')

      await userEvent.click(autoPlaySwitch)

      expect(autoPlaySwitch)!.toHaveAttribute('aria-checked', 'false')
      expect(onChange).toHaveBeenCalled()
    })

    it('should call feature update without onChange callback', async () => {
      renderWithProvider()

      await userEvent.click(screen.getByRole('switch'))

      expect(screen.getByRole('switch'))!.toBeInTheDocument()
    })

    it('should open language listbox and show options', async () => {
      renderWithProvider()

      await userEvent.click(getLanguageSelect())

      const options = await screen.findAllByRole('option')
      expect(options.length).toBeGreaterThanOrEqual(2)
    })

    it('should handle language change', async () => {
      const onChange = vi.fn()
      renderWithProvider({ onChange })

      await userEvent.click(getLanguageSelect())
      const options = await screen.findAllByRole('option')
      expect(options.length).toBeGreaterThan(1)
      await userEvent.click(options[1]!)
      expect(onChange).toHaveBeenCalled()
    })

    it('should handle voice change', async () => {
      const onChange = vi.fn()
      renderWithProvider({ onChange })

      await userEvent.click(getVoiceSelect())
      const options = await screen.findAllByRole('option')
      expect(options.length).toBeGreaterThan(1)
      await userEvent.click(options[1]!)
      expect(onChange).toHaveBeenCalled()
    })

    it('should show selected language option in listbox', async () => {
      renderWithProvider()

      await userEvent.click(getLanguageSelect())
      const options = await screen.findAllByRole('option')
      expect(options.length).toBeGreaterThanOrEqual(1)

      const selectedOption = options.find(opt => opt.textContent?.includes('voice.language.enUS'))
      expect(selectedOption).toBeDefined()
      expect(selectedOption)!.toHaveAttribute('aria-selected', 'true')
    })

    it('should show selected voice option in listbox', async () => {
      renderWithProvider()

      await userEvent.click(getVoiceSelect())
      const options = await screen.findAllByRole('option')
      expect(options.length).toBeGreaterThanOrEqual(1)

      const selectedOption = options.find(opt => opt.textContent?.includes('Alloy'))
      expect(selectedOption).toBeDefined()
      expect(selectedOption)!.toHaveAttribute('aria-selected', 'true')
    })
  })

  // Fallback and boundary scenarios.
  describe('Edge Cases', () => {
    it('should show placeholder and disable voice selection when no languages are available', () => {
      mockLanguages = []
      mockVoiceItems = undefined

      renderWithProvider({}, {
        text2speech: { enabled: true, language: 'en-US', voice: 'alloy', autoPlay: TtsAutoPlay.disabled },
      })

      const placeholderTexts = screen.getAllByText(/placeholder\.select/)
      expect(placeholderTexts.length).toBeGreaterThanOrEqual(2)

      expect(getVoiceSelect()).toHaveAttribute('data-disabled')
    })

    it('should call useAppVoices with empty appId when pathname has no app segment', () => {
      mockPathname = '/configuration'

      renderWithProvider()

      expect(mockUseAppVoices).toHaveBeenCalledWith('', 'en-US')
    })

    it('should render language text when selected language value is empty string', () => {
      mockLanguages = [{ value: '' as string, name: 'Unknown Language', example: '' }]

      renderWithProvider({}, {
        text2speech: { enabled: true, language: '', voice: '', autoPlay: TtsAutoPlay.disabled },
      })

      expect(screen.getByText(/voice\.language\./))!.toBeInTheDocument()
    })
  })
})
