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 { SchemaBuilder } from './SchemaBuilder'
import type { PropertyDef } from './types'

const propsFromKinds = (...kinds: PropertyDef['kind'][]): PropertyDef[] =>
  kinds.map((kind, i) => ({
    id: `id-${i}`,
    name: `field_${i}`,
    kind,
    required: false,
    unique: false,
  }))

describe('SchemaBuilder', () => {
  it('показывает empty state когда полей нет', () => {
    const onChange = vi.fn()
    renderWithI18n(<SchemaBuilder properties={[]} onChange={onChange} />)
    expect(screen.getByText('Полей нет — добавь первое')).toBeInTheDocument()
  })

  it('добавляет новое поле через onChange при клике "Добавить поле"', async () => {
    const user = userEvent.setup()
    const onChange = vi.fn()
    renderWithI18n(<SchemaBuilder properties={[]} onChange={onChange} />)

    await user.click(screen.getByRole('button', { name: /Добавить поле/i }))

    expect(onChange).toHaveBeenCalledTimes(1)
    const next = onChange.mock.calls[0][0] as PropertyDef[]
    expect(next).toHaveLength(1)
    expect(next[0]).toMatchObject({ name: '', kind: 'string', required: false, unique: false })
    expect(next[0].id).toBeTruthy()
  })

  it('рендерит N PropertyEditor по числу properties', () => {
    const onChange = vi.fn()
    renderWithI18n(
      <SchemaBuilder properties={propsFromKinds('string', 'integer', 'enum')} onChange={onChange} />,
    )
    // По 1 заголовку "Поле #N" на каждый property.
    expect(screen.getByText('Поле #1')).toBeInTheDocument()
    expect(screen.getByText('Поле #2')).toBeInTheDocument()
    expect(screen.getByText('Поле #3')).toBeInTheDocument()
  })

  it('moveUp поднимает property вверх', async () => {
    const user = userEvent.setup()
    const onChange = vi.fn()
    const initial = propsFromKinds('string', 'integer')
    renderWithI18n(<SchemaBuilder properties={initial} onChange={onChange} />)

    const upButtons = screen.getAllByRole('button', { name: /Выше/i })
    await user.click(upButtons[1])

    expect(onChange).toHaveBeenCalledTimes(1)
    const next = onChange.mock.calls[0][0] as PropertyDef[]
    expect(next[0].kind).toBe('integer')
    expect(next[1].kind).toBe('string')
  })

  it('moveUp на первом элементе — no-op (kbd disabled, onChange не вызывается)', async () => {
    const user = userEvent.setup()
    const onChange = vi.fn()
    renderWithI18n(<SchemaBuilder properties={propsFromKinds('string', 'integer')} onChange={onChange} />)

    const upButtons = screen.getAllByRole('button', { name: /Выше/i })
    expect(upButtons[0]).toBeDisabled()
    await user.click(upButtons[0])
    expect(onChange).not.toHaveBeenCalled()
  })

  it('moveDown на последнем — disabled', () => {
    const onChange = vi.fn()
    renderWithI18n(<SchemaBuilder properties={propsFromKinds('string', 'integer')} onChange={onChange} />)
    const downButtons = screen.getAllByRole('button', { name: /Ниже/i })
    expect(downButtons[1]).toBeDisabled()
  })

  it('removeAt удаляет указанный property', async () => {
    const user = userEvent.setup()
    const onChange = vi.fn()
    const initial = propsFromKinds('string', 'integer', 'enum')
    renderWithI18n(<SchemaBuilder properties={initial} onChange={onChange} />)

    const deleteButtons = screen.getAllByRole('button', { name: /Удалить/i })
    await user.click(deleteButtons[1])

    const next = onChange.mock.calls[0][0] as PropertyDef[]
    expect(next).toHaveLength(2)
    expect(next.map((p) => p.kind)).toEqual(['string', 'enum'])
  })
})
