// @vitest-environment jsdom
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { render, screen, fireEvent } from '@testing-library/react'
import '@testing-library/jest-dom'
import React from 'react'

const pushMock = vi.fn()
const refreshMock = vi.fn()
const pathnameMock = vi.fn(() => '/dashboard')

vi.mock('next/navigation', () => ({
  useRouter: () => ({ push: pushMock, refresh: refreshMock }),
  usePathname: () => pathnameMock(),
}))

vi.mock('@/actions/active-product', () => ({
  setActiveProductAction: vi.fn(),
}))

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

vi.mock('@/components/ui/dropdown-menu', () => {
  type Props = React.HTMLAttributes<HTMLDivElement> & {
    children?: React.ReactNode
    onClick?: () => void
  }
  const PassThrough = ({ children }: Props) => <>{children}</>
  const Forwarding = ({ children, ...rest }: Props) => <div {...rest}>{children}</div>
  return {
    DropdownMenu: PassThrough,
    DropdownMenuTrigger: Forwarding,
    DropdownMenuContent: PassThrough,
    DropdownMenuItem: ({ children, onClick, className }: Props) => (
      <button type="button" onClick={onClick} className={className} data-testid="dd-item">
        {children}
      </button>
    ),
    DropdownMenuSeparator: () => null,
  }
})

vi.mock('@/components/ui/tooltip', () => {
  type Props = { children?: React.ReactNode }
  const PassThrough = ({ children }: Props) => <>{children}</>
  return {
    Tooltip: PassThrough,
    TooltipContent: PassThrough,
    TooltipProvider: PassThrough,
    TooltipTrigger: PassThrough,
  }
})

vi.mock('@/components/shared/app-icon', () => ({ AppIcon: () => null }))
vi.mock('@/components/shared/user-menu', () => ({ UserMenu: () => null }))
vi.mock('@/components/shared/notifications-bell', () => ({ NotificationsBell: () => null }))
vi.mock('@/components/solo/nav-status-indicators', () => ({
  SoloNavStatusIndicators: () => null,
}))

import { setActiveProductAction } from '@/actions/active-product'
import { toast } from 'sonner'
import { NavBar } from '@/components/shared/nav-bar'

const actionMock = setActiveProductAction as unknown as ReturnType<typeof vi.fn>
const toastSuccess = toast.success as unknown as ReturnType<typeof vi.fn>

const products = [
  { id: 'A', name: 'Alpha' },
  { id: 'B', name: 'Beta' },
]

function renderNavBar(overrides: { isDemo?: boolean; activeProductId?: string } = {}) {
  const isDemo = overrides.isDemo ?? false
  const activeId = overrides.activeProductId ?? 'A'
  const activeProduct = products.find(p => p.id === activeId) ?? null
  return render(
    <NavBar
      isDemo={isDemo}
      roles={[]}
      userId="u1"
      username="user"
      email={null}
      activeProduct={activeProduct}
      products={products}
      hasActiveSprint={false}
      minQuotaPct={100}
    />,
  )
}

beforeEach(() => {
  vi.clearAllMocks()
  actionMock.mockResolvedValue({ success: true })
  pathnameMock.mockReturnValue('/dashboard')
})

describe('NavBar — product switch', () => {
  it('demo: clicking another product navigates via router.push without calling the action', () => {
    renderNavBar({ isDemo: true, activeProductId: 'A' })
    fireEvent.click(screen.getByText('Beta'))
    expect(pushMock).toHaveBeenCalledWith('/products/B')
    expect(actionMock).not.toHaveBeenCalled()
    expect(toastSuccess).not.toHaveBeenCalled()
  })

  it('non-demo: clicking another product calls setActiveProductAction', async () => {
    renderNavBar({ isDemo: false, activeProductId: 'A' })
    fireEvent.click(screen.getByText('Beta'))
    await Promise.resolve()
    expect(actionMock).toHaveBeenCalledWith('B')
  })

  it('non-demo: on /products/A navigates to /products/B', async () => {
    pathnameMock.mockReturnValue('/products/A')
    renderNavBar({ isDemo: false, activeProductId: 'A' })
    fireEvent.click(screen.getByText('Beta'))
    await Promise.resolve()
    await Promise.resolve()
    expect(pushMock).toHaveBeenCalledWith('/products/B')
    expect(toastSuccess).toHaveBeenCalled()
  })

  it('non-demo: on /products/A/sprint/SPR1 navigates to /products/B/sprint', async () => {
    pathnameMock.mockReturnValue('/products/A/sprint/SPR1')
    renderNavBar({ isDemo: false, activeProductId: 'A' })
    fireEvent.click(screen.getByText('Beta'))
    await Promise.resolve()
    await Promise.resolve()
    expect(pushMock).toHaveBeenCalledWith('/products/B/sprint')
    expect(toastSuccess).toHaveBeenCalled()
  })

  it('non-demo: on /products/A/solo navigates to /products/B/solo', async () => {
    pathnameMock.mockReturnValue('/products/A/solo')
    renderNavBar({ isDemo: false, activeProductId: 'A' })
    fireEvent.click(screen.getByText('Beta'))
    await Promise.resolve()
    await Promise.resolve()
    expect(pushMock).toHaveBeenCalledWith('/products/B/solo')
    expect(toastSuccess).toHaveBeenCalled()
  })

  it('non-demo: on /dashboard calls router.refresh and not router.push', async () => {
    pathnameMock.mockReturnValue('/dashboard')
    renderNavBar({ isDemo: false, activeProductId: 'A' })
    fireEvent.click(screen.getByText('Beta'))
    await Promise.resolve()
    await Promise.resolve()
    expect(refreshMock).toHaveBeenCalled()
    expect(pushMock).not.toHaveBeenCalled()
    expect(toastSuccess).toHaveBeenCalled()
  })
})

describe('NavBar — URL-derived active product (demo only)', () => {
  it('demo: label and dropdown highlight follow pathname, not the activeProduct prop', () => {
    pathnameMock.mockReturnValue('/products/B/sprint')
    const { container } = renderNavBar({ isDemo: true, activeProductId: 'A' })
    const trigger = container.querySelector('[data-debug-id="nav-bar__product-switcher"]')
    expect(trigger?.textContent).toContain('Beta')
    expect(trigger?.textContent).not.toContain('Alpha')
    const items = screen.getAllByTestId('dd-item')
    const itemB = items.find(el => el.textContent?.includes('Beta'))
    expect(itemB?.className).toContain('bg-primary-container')
    const itemA = items.find(el => el.textContent?.includes('Alpha'))
    expect(itemA?.className ?? '').not.toContain('bg-primary-container')
  })

  it('non-demo: pathname does NOT override the activeProduct prop', () => {
    pathnameMock.mockReturnValue('/products/B/sprint')
    renderNavBar({ isDemo: false, activeProductId: 'A' })
    // Label still reflects server-rendered activeProduct (Alpha)
    const items = screen.getAllByTestId('dd-item')
    const itemA = items.find(el => el.textContent?.includes('Alpha'))
    expect(itemA?.className).toContain('bg-primary-container')
  })
})
