import { render, screen, fireEvent, waitFor } from "@testing-library/react"
import userEvent from "@testing-library/user-event"
import { useState } from "react"
import { test, expect, vi } from "vitest"
import { RecordEditor } from "./RecordEditor"
import type { RecordDTO } from "@/api/types"

function Harness({
  initial,
  onChange,
}: {
  initial: RecordDTO[]
  onChange: (records: RecordDTO[]) => void
}) {
  const [value, setValue] = useState<RecordDTO[]>(initial)
  return (
    <RecordEditor
      value={value}
      onChange={(next) => {
        setValue(next)
        onChange(next)
      }}
    />
  )
}

test("добавление записи вызывает onChange с новой пустой записью типа A", async () => {
  const onChange = vi.fn()
  const user = userEvent.setup()
  render(<Harness initial={[]} onChange={onChange} />)

  await user.click(screen.getByRole("button", { name: /добавить запись/i }))

  expect(onChange).toHaveBeenCalledWith([{ type: "A", name: "", ttl: 3600, values: [""] }])
})

test("изменение полей записи вызывает onChange с корректным массивом", async () => {
  const onChange = vi.fn()
  render(
    <Harness
      initial={[{ type: "A", name: "", ttl: 3600, values: [""] }]}
      onChange={onChange}
    />,
  )

  fireEvent.change(screen.getByLabelText(/имя записи 1/i), { target: { value: "www" } })
  fireEvent.change(screen.getByLabelText(/ttl записи 1/i), { target: { value: "300" } })
  fireEvent.change(screen.getByLabelText(/значения записи 1/i), {
    target: { value: "192.0.2.1" },
  })

  await waitFor(() =>
    expect(onChange).toHaveBeenLastCalledWith([
      { type: "A", name: "www", ttl: 300, values: ["192.0.2.1"] },
    ]),
  )
})

test("несколько значений в textarea дают несколько элементов values", async () => {
  const onChange = vi.fn()
  render(
    <Harness
      initial={[{ type: "NS", name: "@", ttl: 3600, values: [""] }]}
      onChange={onChange}
    />,
  )

  fireEvent.change(screen.getByLabelText(/значения записи 1/i), {
    target: { value: "ns1.example.com.\nns2.example.com." },
  })

  await waitFor(() =>
    expect(onChange).toHaveBeenLastCalledWith([
      {
        type: "NS",
        name: "@",
        ttl: 3600,
        values: ["ns1.example.com.", "ns2.example.com."],
      },
    ]),
  )
})

test("выбор типа SRV и составное значение prio weight port target", async () => {
  const onChange = vi.fn()
  const user = userEvent.setup()
  render(
    <Harness
      initial={[{ type: "A", name: "_sip._tcp", ttl: 3600, values: [""] }]}
      onChange={onChange}
    />,
  )

  await user.click(screen.getByRole("combobox", { name: /тип записи 1/i }))
  await user.click(await screen.findByRole("option", { name: /^srv$/i }))

  fireEvent.change(screen.getByLabelText(/значения записи 1/i), {
    target: { value: "10 5 5060 sipserver.example.com." },
  })

  await waitFor(() =>
    expect(onChange).toHaveBeenLastCalledWith([
      {
        type: "SRV",
        name: "_sip._tcp",
        ttl: 3600,
        values: ["10 5 5060 sipserver.example.com."],
      },
    ]),
  )
})

test("удаление записи вызывает onChange без удалённой записи", async () => {
  const onChange = vi.fn()
  const user = userEvent.setup()
  const initial: RecordDTO[] = [
    { type: "A", name: "a", ttl: 3600, values: ["1.1.1.1"] },
    { type: "A", name: "b", ttl: 3600, values: ["2.2.2.2"] },
  ]
  render(<Harness initial={initial} onChange={onChange} />)

  await user.click(screen.getByRole("button", { name: /удалить запись 1/i }))

  expect(onChange).toHaveBeenLastCalledWith([
    { type: "A", name: "b", ttl: 3600, values: ["2.2.2.2"] },
  ])
})

test("mono-шрифт применён к полям name и values", () => {
  render(
    <Harness
      initial={[{ type: "A", name: "www", ttl: 3600, values: ["1.2.3.4"] }]}
      onChange={vi.fn()}
    />,
  )

  expect(screen.getByLabelText(/имя записи 1/i)).toHaveClass("font-dns")
  expect(screen.getByLabelText(/значения записи 1/i)).toHaveClass("font-dns")
})
