import type { ReactNode } from 'react'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'

import type { Webhook } from '@/types/webhook'
import { WebhookFormModal } from './WebhookFormModal'

const createWebhookMock = vi.fn()
const updateWebhookMock = vi.fn()
const messageSuccessMock = vi.fn()
const messageErrorMock = vi.fn()
const formApi = {
  validateFields: vi.fn(),
  setFieldsValue: vi.fn(),
  resetFields: vi.fn(),
}

vi.mock('antd', () => {
  const Form = ({
    children,
  }: {
    children?: ReactNode
  }) => <form>{children}</form>

  return {
    Form: Object.assign(Form, {
      useForm: () => [formApi],
      Item: ({
        label,
        children,
      }: {
        label?: ReactNode
        children?: ReactNode
      }) => (
        <div>
          {label ? <span>{label}</span> : null}
          {children}
        </div>
      ),
    }),
    Input: Object.assign(({
      placeholder,
    }: {
      placeholder?: string
    }) => <input placeholder={placeholder} readOnly />, {
      Password: ({ placeholder }: { placeholder?: string }) => (
        <input placeholder={placeholder} type="password" readOnly />
      ),
    }),
    Modal: ({
      open,
      title,
      onOk,
      onCancel,
      children,
      confirmLoading,
    }: {
      open: boolean
      title?: ReactNode
      onOk?: () => void
      onCancel?: () => void
      children?: ReactNode
      confirmLoading?: boolean
    }) => (
      open ? (
        <div data-testid="webhook-form-modal-root">
          <h1>{title}</h1>
          <div>{`loading:${String(confirmLoading ?? false)}`}</div>
          {children}
          <button type="button" onClick={onOk}>modal ok</button>
          <button type="button" onClick={onCancel}>modal cancel</button>
        </div>
      ) : null
    ),
    Select: ({
      placeholder,
      options = [],
    }: {
      placeholder?: string
      options?: Array<{ value: string, label: ReactNode }>
    }) => (
      <select aria-label={placeholder ?? 'select'}>
        {options.map((option) => (
          <option key={option.value} value={option.value}>
            {option.label}
          </option>
        ))}
      </select>
    ),
    message: {
      success: (content: string) => messageSuccessMock(content),
      error: (content: string) => messageErrorMock(content),
    },
  }
})

vi.mock('@/services/webhooks', () => ({
  createWebhook: (payload: unknown) => createWebhookMock(payload),
  updateWebhook: (id: number, payload: unknown) => updateWebhookMock(id, payload),
}))

function buildWebhook(): Webhook {
  return {
    id: 7,
    name: 'Audit Hook',
    url: 'https://audit.example.com/webhook',
    events: ['user.registered', 'user.deleted'],
    status: 1,
    max_retries: 3,
    timeout_sec: 15,
    created_by: 1,
    created_at: '2026-03-28 09:00:00',
    updated_at: '2026-03-28 09:10:00',
  }
}

describe('WebhookFormModal', () => {
  beforeEach(() => {
    createWebhookMock.mockReset()
    updateWebhookMock.mockReset()
    messageSuccessMock.mockReset()
    messageErrorMock.mockReset()
    formApi.validateFields.mockReset()
    formApi.setFieldsValue.mockReset()
    formApi.resetFields.mockReset()
  })

  afterEach(() => {
    vi.restoreAllMocks()
  })

  it('resets create mode, renders event options, and submits create payloads', async () => {
    const user = userEvent.setup()
    const onSuccess = vi.fn()

    formApi.validateFields.mockResolvedValue({
      name: 'Created Hook',
      url: 'https://created.example.com/webhook',
      secret: 'secret-token',
      events: ['user.registered'],
    })
    createWebhookMock.mockResolvedValue(undefined)

    render(
      <WebhookFormModal
        open
        webhook={null}
        onSuccess={onSuccess}
        onClose={vi.fn()}
      />,
    )

    expect(formApi.resetFields).toHaveBeenCalledTimes(1)
    expect(screen.getByText('用户注册')).toBeInTheDocument()

    await user.click(screen.getByRole('button', { name: 'modal ok' }))

    await waitFor(() => expect(createWebhookMock).toHaveBeenCalledWith({
      name: 'Created Hook',
      url: 'https://created.example.com/webhook',
      secret: 'secret-token',
      events: ['user.registered'],
    }))
    expect(messageSuccessMock).toHaveBeenCalledTimes(1)
    expect(onSuccess).toHaveBeenCalledTimes(1)
  })

  it('prefills edit mode and updates editable fields only', async () => {
    const user = userEvent.setup()
    const webhook = buildWebhook()

    formApi.validateFields.mockResolvedValue({
      name: 'Updated Hook',
      url: 'https://updated.example.com/webhook',
      secret: 'ignored-secret',
      events: ['user.deleted'],
    })
    updateWebhookMock.mockResolvedValue(undefined)

    render(
      <WebhookFormModal
        open
        webhook={webhook}
        onSuccess={vi.fn()}
        onClose={vi.fn()}
      />,
    )

    expect(formApi.setFieldsValue).toHaveBeenCalledWith({
      name: 'Audit Hook',
      url: 'https://audit.example.com/webhook',
      events: ['user.registered', 'user.deleted'],
    })

    await user.click(screen.getByRole('button', { name: 'modal ok' }))

    await waitFor(() => expect(updateWebhookMock).toHaveBeenCalledWith(7, {
      name: 'Updated Hook',
      url: 'https://updated.example.com/webhook',
      events: ['user.deleted'],
    }))
    expect(messageSuccessMock).toHaveBeenCalledTimes(1)
  })

  it('swallows validation errors and surfaces service failures', async () => {
    const user = userEvent.setup()

    formApi.validateFields.mockRejectedValueOnce({ errorFields: [{ name: ['name'] }] })

    const { rerender } = render(
      <WebhookFormModal
        open
        webhook={null}
        onSuccess={vi.fn()}
        onClose={vi.fn()}
      />,
    )

    await user.click(screen.getByRole('button', { name: 'modal ok' }))

    await waitFor(() => expect(createWebhookMock).not.toHaveBeenCalled())
    expect(messageErrorMock).not.toHaveBeenCalled()

    formApi.validateFields.mockResolvedValueOnce({
      name: 'Broken Hook',
      url: 'https://broken.example.com/webhook',
      secret: '',
      events: ['user.registered'],
    })
    createWebhookMock.mockRejectedValueOnce(new Error('save failed'))

    rerender(
      <WebhookFormModal
        open
        webhook={null}
        onSuccess={vi.fn()}
        onClose={vi.fn()}
      />,
    )

    await user.click(screen.getByRole('button', { name: 'modal ok' }))

    await waitFor(() => expect(messageErrorMock).toHaveBeenCalledWith('save failed'))
  })
})
