import { describe, it, expect, vi } from 'vitest'
import { render, screen, waitFor } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { MemoryRouter } from 'react-router-dom'
import React from 'react'
import { ProductForm } from '../../../features/products/components/ProductForm'
import type { ProductTypeListItem } from '../../../features/product-types/types'

vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } }))

const ptRequiresCategory: ProductTypeListItem = {
  id: 1,
  nombre: 'Con categoría',
  hasDuration: false,
  requiresText: false,
  requiresCategory: true,
  isBundle: false,
  allowImages: false,
  isActive: true,
}

const ptHasDuration: ProductTypeListItem = {
  id: 2,
  nombre: 'Con duración',
  hasDuration: true,
  requiresText: false,
  requiresCategory: false,
  isBundle: false,
  allowImages: false,
  isActive: true,
}

const ptSimple: ProductTypeListItem = {
  id: 3,
  nombre: 'Simple',
  hasDuration: false,
  requiresText: false,
  requiresCategory: false,
  isBundle: false,
  allowImages: false,
  isActive: true,
}

function wrap(children: React.ReactNode) {
  const qc = new QueryClient({
    defaultOptions: { queries: { retry: false }, mutations: { retry: false } },
  })
  return render(
    <QueryClientProvider client={qc}>
      <MemoryRouter>{children}</MemoryRouter>
    </QueryClientProvider>,
  )
}

// ─── ProductForm — no ProductType selected ────────────────────────────────

describe('ProductForm — no ProductType selected', () => {
  it('hides RubroId and PriceDurationDays fields when no ProductType is selected', () => {
    wrap(
      <ProductForm
        productTypes={[ptRequiresCategory, ptHasDuration, ptSimple]}
        onSubmit={vi.fn()}
        onCancel={vi.fn()}
      />,
    )
    expect(screen.queryByLabelText(/rubro/i)).not.toBeInTheDocument()
    expect(screen.queryByLabelText(/días de duración/i)).not.toBeInTheDocument()
  })
})

// ─── ProductForm — requiresCategory flag ─────────────────────────────────

describe('ProductForm — requiresCategory flag', () => {
  it('shows RubroId field when ProductType has requiresCategory=true', async () => {
    wrap(
      <ProductForm
        productTypes={[ptRequiresCategory, ptSimple]}
        onSubmit={vi.fn()}
        onCancel={vi.fn()}
        defaultValues={{ productTypeId: 1 }}
      />,
    )
    await waitFor(() =>
      expect(screen.getByLabelText(/id de rubro/i)).toBeInTheDocument(),
    )
  })

  it('hides RubroId field when ProductType has requiresCategory=false', async () => {
    wrap(
      <ProductForm
        productTypes={[ptSimple]}
        onSubmit={vi.fn()}
        onCancel={vi.fn()}
        defaultValues={{ productTypeId: 3 }}
      />,
    )
    await waitFor(() =>
      expect(screen.queryByLabelText(/id de rubro/i)).not.toBeInTheDocument(),
    )
  })
})

// ─── ProductForm — hasDuration flag ──────────────────────────────────────

describe('ProductForm — hasDuration flag', () => {
  it('shows PriceDurationDays when ProductType has hasDuration=true', async () => {
    wrap(
      <ProductForm
        productTypes={[ptHasDuration]}
        onSubmit={vi.fn()}
        onCancel={vi.fn()}
        defaultValues={{ productTypeId: 2 }}
      />,
    )
    await waitFor(() =>
      expect(screen.getByLabelText(/días de duración/i)).toBeInTheDocument(),
    )
  })

  it('hides PriceDurationDays when ProductType has hasDuration=false', async () => {
    wrap(
      <ProductForm
        productTypes={[ptSimple]}
        onSubmit={vi.fn()}
        onCancel={vi.fn()}
        defaultValues={{ productTypeId: 3 }}
      />,
    )
    await waitFor(() =>
      expect(screen.queryByLabelText(/días de duración/i)).not.toBeInTheDocument(),
    )
  })
})

// ─── ProductForm — submit normalization ──────────────────────────────────

describe('ProductForm — submit normalization', () => {
  it('nulls out rubroId when requiresCategory=false on submit', async () => {
    const onSubmit = vi.fn()
    wrap(
      <ProductForm
        productTypes={[ptSimple]}
        onSubmit={onSubmit}
        onCancel={vi.fn()}
        defaultValues={{ productTypeId: 3 }}
      />,
    )
    await userEvent.type(screen.getByLabelText(/nombre/i), 'Prod Test')
    await userEvent.type(screen.getByLabelText(/id de medio/i), '1')
    await userEvent.type(screen.getByLabelText(/precio base/i), '100')
    await userEvent.click(screen.getByRole('button', { name: /guardar/i }))
    await waitFor(() => {
      expect(onSubmit).toHaveBeenCalled()
      const payload = onSubmit.mock.calls[0][0]
      expect(payload.rubroId).toBeNull()
    })
  })

  it('nulls out priceDurationDays when hasDuration=false on submit', async () => {
    const onSubmit = vi.fn()
    wrap(
      <ProductForm
        productTypes={[ptSimple]}
        onSubmit={onSubmit}
        onCancel={vi.fn()}
        defaultValues={{ productTypeId: 3 }}
      />,
    )
    await userEvent.type(screen.getByLabelText(/nombre/i), 'Prod Test2')
    await userEvent.type(screen.getByLabelText(/id de medio/i), '1')
    await userEvent.type(screen.getByLabelText(/precio base/i), '100')
    await userEvent.click(screen.getByRole('button', { name: /guardar/i }))
    await waitFor(() => {
      expect(onSubmit).toHaveBeenCalled()
      const payload = onSubmit.mock.calls[0][0]
      expect(payload.priceDurationDays).toBeNull()
    })
  })

  it('calls onCancel when cancel button is clicked', async () => {
    const onCancel = vi.fn()
    wrap(
      <ProductForm
        productTypes={[ptSimple]}
        onSubmit={vi.fn()}
        onCancel={onCancel}
      />,
    )
    await userEvent.click(screen.getByRole('button', { name: /cancelar/i }))
    expect(onCancel).toHaveBeenCalled()
  })
})
