import { describe, it, expect, vi } from 'vitest'
import { screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { renderWithI18n } from '@/test/render'
import { SchemaDrivenForm } from './SchemaDrivenForm'
import type { FlattenedRecord, JsonSchema } from '@/api/client'

// Stub useReferencedRecords so tests don't need a QueryClient. Each test
// can override via mockReturnValue.
type MockResult = {
  data: FlattenedRecord[] | undefined
  isLoading: boolean
  isError: boolean
}
const mockUseReferencedRecords = vi.fn<(name: string | undefined) => MockResult>(
  () => ({ data: undefined, isLoading: false, isError: false }),
)
vi.mock('@/api/queries', () => ({
  useReferencedRecords: (name: string | undefined) => mockUseReferencedRecords(name),
}))

const minimalSchema: JsonSchema = {
  $schema: 'http://json-schema.org/draft-07/schema#',
  type: 'object',
  additionalProperties: false,
  required: ['code', 'name'],
  'x-id-source': 'code',
  properties: {
    code: { type: 'string', minLength: 1, 'x-unique': true },
    name: { type: 'string', minLength: 1 },
    description: { type: 'string' },
  },
} as JsonSchema

describe('SchemaDrivenForm', () => {
  it('рендерит идентификационный таб с required-полями', () => {
    renderWithI18n(
      <SchemaDrivenForm
        schema={minimalSchema}
        supportedLocales={['ru-RU', 'en-US']}
        defaultLocale="ru-RU"
        mode="create"
        isPending={false}
        onSubmit={() => {}}
        onCancel={() => {}}
      />,
    )
    // x-id-source: 'code' → бизнес-ключ автогенерится, показывается hint
    expect(screen.getByText(/Бизнес-ключ создастся автоматически/)).toBeInTheDocument()
    // Required-поля code/name на табе "Идентификация". i18n field.code=Код,
    // field.name=Наименование (см. src/i18n.ts).
    expect(screen.getByText('Код')).toBeInTheDocument()
    expect(screen.getByText('Наименование')).toBeInTheDocument()
  })

  it('переключение на таб "Дополнительно" показывает optional поля', async () => {
    const user = userEvent.setup()
    renderWithI18n(
      <SchemaDrivenForm
        schema={minimalSchema}
        supportedLocales={['ru-RU']}
        defaultLocale="ru-RU"
        mode="create"
        isPending={false}
        onSubmit={() => {}}
        onCancel={() => {}}
      />,
    )
    // Radix Tabs (Stage 3.9) использует role="tab" — semantically correct.
    await user.click(screen.getByRole('tab', { name: /Дополнительно/i }))
    // description (optional) теперь виден. i18n field.description=Описание.
    expect(screen.getByText('Описание')).toBeInTheDocument()
  })

  it('disabled Save кнопка пока isPending', () => {
    renderWithI18n(
      <SchemaDrivenForm
        schema={minimalSchema}
        supportedLocales={['ru-RU']}
        defaultLocale="ru-RU"
        mode="create"
        isPending={true}
        onSubmit={() => {}}
        onCancel={() => {}}
      />,
    )
    const saveBtn = screen.getByRole('button', { name: /Сохранение/i })
    expect(saveBtn).toBeDisabled()
  })

  it('Cancel вызывает onCancel', async () => {
    const user = userEvent.setup()
    const onCancel = vi.fn()
    renderWithI18n(
      <SchemaDrivenForm
        schema={minimalSchema}
        supportedLocales={['ru-RU']}
        defaultLocale="ru-RU"
        mode="create"
        isPending={false}
        onSubmit={() => {}}
        onCancel={onCancel}
      />,
    )
    await user.click(screen.getByRole('button', { name: 'Отмена' }))
    expect(onCancel).toHaveBeenCalledTimes(1)
  })

  it('x-references поле рендерится как SingleSelect с подгруженными опциями', async () => {
    const fkRecords: FlattenedRecord[] = [
      {
        id: '1',
        businessKey: 'OPERATIONAL',
        data: { code: 'OPERATIONAL', name: { 'ru-RU': 'Действующий' } },
        dataScope: 'PUBLIC',
        validFrom: '2020-01-01',
        validTo: '9999-12-31',
      },
      {
        id: '2',
        businessKey: 'LOST',
        data: { code: 'LOST', name: { 'ru-RU': 'Утерян' } },
        dataScope: 'PUBLIC',
        validFrom: '2020-01-01',
        validTo: '9999-12-31',
      },
    ]
    mockUseReferencedRecords.mockReturnValue({
      data: fkRecords,
      isLoading: false,
      isError: false,
    })

    const fkSchema: JsonSchema = {
      $schema: 'http://json-schema.org/draft-07/schema#',
      type: 'object',
      additionalProperties: false,
      required: ['code', 'status'],
      'x-id-source': 'code',
      properties: {
        code: { type: 'string', minLength: 1, 'x-unique': true },
        status: {
          type: 'string',
          'x-references': 'spacecraft_status.code',
          description: 'Статус КА',
        },
      },
    } as JsonSchema

    renderWithI18n(
      <SchemaDrivenForm
        schema={fkSchema}
        supportedLocales={['ru-RU']}
        defaultLocale="ru-RU"
        mode="create"
        isPending={false}
        onSubmit={() => {}}
        onCancel={() => {}}
      />,
    )
    expect(mockUseReferencedRecords).toHaveBeenCalledWith('spacecraft_status')
    // Hint показывает FK target.
    expect(screen.getByText(/Статус КА/)).toBeInTheDocument()
    // Native <select> рендерит options сразу в DOM. Проверяем что обе
    // опции с локализованным name присутствуют.
    expect(screen.getByRole('option', { name: 'OPERATIONAL — Действующий' })).toBeInTheDocument()
    expect(screen.getByRole('option', { name: 'LOST — Утерян' })).toBeInTheDocument()
  })

  it('x-references fallback на TextInput когда target dict недоступен (scope-hide)', () => {
    mockUseReferencedRecords.mockReturnValue({
      data: [],
      isLoading: false,
      isError: false,
    })

    const fkSchema: JsonSchema = {
      $schema: 'http://json-schema.org/draft-07/schema#',
      type: 'object',
      additionalProperties: false,
      required: ['code', 'status'],
      'x-id-source': 'code',
      properties: {
        code: { type: 'string', minLength: 1, 'x-unique': true },
        status: {
          type: 'string',
          'x-references': 'restricted_dict.code',
        },
      },
    } as JsonSchema

    renderWithI18n(
      <SchemaDrivenForm
        schema={fkSchema}
        supportedLocales={['ru-RU']}
        defaultLocale="ru-RU"
        mode="create"
        isPending={false}
        onSubmit={() => {}}
        onCancel={() => {}}
      />,
    )
    // Hint показывает FK target — admin понимает что валидация серверная.
    expect(screen.getByText(/FK на restricted_dict\.code/)).toBeInTheDocument()
  })

  it('serverError рендерится как Alert', () => {
    renderWithI18n(
      <SchemaDrivenForm
        schema={minimalSchema}
        supportedLocales={['ru-RU']}
        defaultLocale="ru-RU"
        mode="create"
        isPending={false}
        serverError="Дубликат business_key"
        onSubmit={() => {}}
        onCancel={() => {}}
      />,
    )
    expect(screen.getByText('Дубликат business_key')).toBeInTheDocument()
  })
})
