import { describe, it, expect, vi } from 'vitest'
import { render, screen } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { CategoryTree } from '../../../features/rubros/components/CategoryTree'
import type { RubroTreeNode } from '../../../features/rubros/types'

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

const makeTree = (): RubroTreeNode[] => [
  {
    id: 1,
    nombre: 'Autos',
    orden: 1,
    activo: true,
    parentId: null,
    tarifarioBaseId: null,
    hijos: [
      {
        id: 2,
        nombre: 'Sedanes',
        orden: 1,
        activo: true,
        parentId: 1,
        tarifarioBaseId: null,
        hijos: [
          {
            id: 3,
            nombre: 'Sedanes chicos',
            orden: 1,
            activo: true,
            parentId: 2,
            tarifarioBaseId: null,
            hijos: [],
          },
        ],
      },
    ],
  },
  {
    id: 4,
    nombre: 'Inmuebles',
    orden: 2,
    activo: false,
    parentId: null,
    tarifarioBaseId: null,
    hijos: [],
  },
]

const noop = vi.fn()

describe('CategoryTree', () => {
  it('renders empty state when no nodes', () => {
    render(
      <CategoryTree nodes={[]} onEdit={noop} onDelete={noop} onAddChild={noop} onMove={noop} canEdit={false} />,
    )
    expect(screen.getByText(/no hay rubros/i)).toBeInTheDocument()
  })

  it('renders all root node names', () => {
    render(
      <CategoryTree nodes={makeTree()} onEdit={noop} onDelete={noop} onAddChild={noop} onMove={noop} canEdit={false} />,
    )
    expect(screen.getByText('Autos')).toBeInTheDocument()
    expect(screen.getByText('Inmuebles')).toBeInTheDocument()
  })

  it('shows children after expanding a node', async () => {
    render(
      <CategoryTree nodes={makeTree()} onEdit={noop} onDelete={noop} onAddChild={noop} onMove={noop} canEdit={false} />,
    )
    // Sedanes should be hidden initially
    expect(screen.queryByText('Sedanes')).not.toBeInTheDocument()
    // Expand Autos (click the toggle)
    await userEvent.click(screen.getByRole('button', { name: /expandir autos/i }))
    expect(screen.getByText('Sedanes')).toBeInTheDocument()
  })

  it('hides action buttons when canEdit is false', () => {
    render(
      <CategoryTree nodes={makeTree()} onEdit={noop} onDelete={noop} onAddChild={noop} onMove={noop} canEdit={false} />,
    )
    expect(screen.queryByRole('button', { name: /editar/i })).not.toBeInTheDocument()
    expect(screen.queryByRole('button', { name: /eliminar/i })).not.toBeInTheDocument()
  })

  it('shows action buttons when canEdit is true', () => {
    render(
      <CategoryTree nodes={makeTree()} onEdit={noop} onDelete={noop} onAddChild={noop} onMove={noop} canEdit={true} />,
    )
    const editBtns = screen.getAllByRole('button', { name: /editar/i })
    expect(editBtns.length).toBeGreaterThan(0)
  })

  it('shows "inactivo" badge on inactive nodes', () => {
    render(
      <CategoryTree nodes={makeTree()} onEdit={noop} onDelete={noop} onAddChild={noop} onMove={noop} canEdit={false} />,
    )
    expect(screen.getByText('inactivo')).toBeInTheDocument()
  })

  it('renders 3-level deep tree when expanded', async () => {
    render(
      <CategoryTree nodes={makeTree()} onEdit={noop} onDelete={noop} onAddChild={noop} onMove={noop} canEdit={false} />,
    )
    await userEvent.click(screen.getByRole('button', { name: /expandir autos/i }))
    expect(screen.getByText('Sedanes')).toBeInTheDocument()
    await userEvent.click(screen.getByRole('button', { name: /expandir sedanes/i }))
    expect(screen.getByText('Sedanes chicos')).toBeInTheDocument()
  })
})

// ── CAT-002: tieneAvisos disables "Agregar subrubro" button ──────────────────

describe('CategoryTreeNode tieneAvisos (CAT-002)', () => {
  it('BotonAgregarSubrubro_Disabled_CuandoTieneAvisosTrue', () => {
    const nodeConAvisos: RubroTreeNode = {
      id: 10,
      nombre: 'ConAvisos',
      orden: 1,
      activo: true,
      parentId: null,
      tarifarioBaseId: null,
      tieneAvisos: true,
      hijos: [],
    }
    render(
      <CategoryTree
        nodes={[nodeConAvisos]}
        onEdit={noop}
        onDelete={noop}
        onAddChild={noop}
        onMove={noop}
        canEdit={true}
      />,
    )
    const addBtn = screen.getByRole('button', { name: /agregar subrubro en conavisos/i })
    expect(addBtn).toBeDisabled()
    expect(addBtn).toHaveAttribute('title')
    expect(addBtn.getAttribute('title')).toBe(
      'El rubro contiene avisos asignados. Muévalos antes de agregar sub-rubros.',
    )
  })

  it('BotonAgregarSubrubro_Enabled_CuandoTieneAvisosFalse', () => {
    const nodeSinAvisos: RubroTreeNode = {
      id: 11,
      nombre: 'SinAvisos',
      orden: 1,
      activo: true,
      parentId: null,
      tarifarioBaseId: null,
      tieneAvisos: false,
      hijos: [],
    }
    render(
      <CategoryTree
        nodes={[nodeSinAvisos]}
        onEdit={noop}
        onDelete={noop}
        onAddChild={noop}
        onMove={noop}
        canEdit={true}
      />,
    )
    const addBtn = screen.getByRole('button', { name: /agregar subrubro en sinavisos/i })
    expect(addBtn).not.toBeDisabled()
  })
})

describe('CategoryTreeNode depth guard', () => {
  it('renders depth warning when depth exceeds 10', () => {
    // Build a deeply nested node at depth 11
    const deepNode: RubroTreeNode = {
      id: 99,
      nombre: 'Deep',
      orden: 1,
      activo: true,
      parentId: null,
      tarifarioBaseId: null,
      hijos: [],
    }
    // Render with depth=11 via internal mechanism — we test via CategoryTree with a manually-crafted prop
    // CategoryTreeNode is not exported standalone; CategoryTree handles depth internally.
    // We verify no stack overflow with a highly-nested tree.
    let current: RubroTreeNode = { ...deepNode, id: 100, nombre: 'Level 11', hijos: [] }
    for (let i = 10; i >= 0; i--) {
      current = { ...deepNode, id: i, nombre: `Level ${i}`, hijos: [current] }
    }
    // Should render without crashing; depth guard warning visible for deepest
    render(
      <CategoryTree nodes={[current]} onEdit={noop} onDelete={noop} onAddChild={noop} onMove={noop} canEdit={false} />,
    )
    // Level 0 should always render
    expect(screen.getByText('Level 0')).toBeInTheDocument()
  })
})
