// @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(() => '/products/p1/sprint')

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

vi.mock('@/actions/active-sprint', () => ({
  setActiveSprintAction: vi.fn(),
  switchActiveSprintAction: vi.fn(),
  clearActiveSprintAction: vi.fn(),
}))

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

const isDemoMock = { value: false }
const workflowMock: {
  value:
    | { pendingSprintDraft?: Record<string, { goal: string } | undefined> }
    | undefined
} = { value: undefined }
// Mock-state shape moet alle paden dekken die SprintSwitcher selecteert:
// - s.context.isDemo (oude code)
// - s.entities.settings.workflow?.pendingSprintDraft?.[productId]?.goal (PBI-79)
type MockStoreState = {
  context: { isDemo: boolean }
  entities: {
    settings: {
      workflow?: {
        pendingSprintDraft?: Record<string, { goal: string } | undefined>
      }
    }
  }
}
vi.mock('@/stores/user-settings/store', () => ({
  useUserSettingsStore: (selector: (s: MockStoreState) => unknown) =>
    selector({
      context: { isDemo: isDemoMock.value },
      entities: { settings: { workflow: workflowMock.value } },
    }),
}))

vi.mock('@/components/ui/dropdown-menu', () => {
  type Props = { children?: React.ReactNode; onClick?: () => void; className?: string }
  const PassThrough = ({ children }: Props) => <>{children}</>
  return {
    DropdownMenu: PassThrough,
    DropdownMenuTrigger: PassThrough,
    DropdownMenuContent: PassThrough,
    DropdownMenuItem: ({ children, onClick, className }: Props) => (
      <button type="button" onClick={onClick} className={className}>
        {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,
  }
})

import { switchActiveSprintAction } from '@/actions/active-sprint'
import { toast } from 'sonner'
import { SprintSwitcher } from '@/components/shared/sprint-switcher'

const actionMock = switchActiveSprintAction as unknown as ReturnType<typeof vi.fn>
const toastError = toast.error as unknown as ReturnType<typeof vi.fn>
const toastSuccess = toast.success as unknown as ReturnType<typeof vi.fn>

const sprints = [
  { id: 's1', code: 'SP-1', sprint_goal: 'Goal 1', status: 'open' as const },
  { id: 's2', code: 'SP-2', sprint_goal: 'Goal 2', status: 'open' as const },
]

beforeEach(() => {
  vi.clearAllMocks()
  isDemoMock.value = false
  workflowMock.value = undefined
  actionMock.mockResolvedValue({ success: true })
  pathnameMock.mockReturnValue('/products/p1/sprint')
})

describe('SprintSwitcher', () => {
  it('demo: clicking another sprint navigates via router.push without calling the action', () => {
    isDemoMock.value = true
    render(
      <SprintSwitcher
        productId="p1"
        sprints={sprints}
        activeSprint={sprints[0]}
        buildingSprintIds={[]}
      />,
    )
    fireEvent.click(screen.getByText('Goal 2'))
    expect(pushMock).toHaveBeenCalledWith('/products/p1/sprint/s2')
    expect(actionMock).not.toHaveBeenCalled()
    expect(toastError).not.toHaveBeenCalled()
    expect(toastSuccess).not.toHaveBeenCalled()
  })

  it('non-demo: clicking another sprint calls setActiveSprintAction', async () => {
    isDemoMock.value = false
    render(
      <SprintSwitcher
        productId="p1"
        sprints={sprints}
        activeSprint={sprints[0]}
        buildingSprintIds={[]}
      />,
    )
    fireEvent.click(screen.getByText('Goal 2'))
    // Wait microtask for the transition to flush.
    await Promise.resolve()
    expect(actionMock).toHaveBeenCalledWith('p1', 's2')
  })

  it('clicking the already-active sprint does nothing', () => {
    isDemoMock.value = true
    render(
      <SprintSwitcher
        productId="p1"
        sprints={sprints}
        activeSprint={sprints[0]}
        buildingSprintIds={[]}
      />,
    )
    fireEvent.click(screen.getByText('Goal 1'))
    expect(pushMock).not.toHaveBeenCalled()
    expect(actionMock).not.toHaveBeenCalled()
  })

  it('shows the concept-sprint on the trigger when a draft is pending (G5)', () => {
    workflowMock.value = { pendingSprintDraft: { p1: { goal: 'Test goal' } } }
    render(
      <SprintSwitcher
        productId="p1"
        sprints={sprints}
        activeSprint={null}
        buildingSprintIds={[]}
      />,
    )
    expect(screen.getByText('⚙ Concept — Test goal')).toBeInTheDocument()
  })

  it('shows no concept label on the trigger when no draft is pending', () => {
    render(
      <SprintSwitcher
        productId="p1"
        sprints={sprints}
        activeSprint={sprints[0]}
        buildingSprintIds={[]}
      />,
    )
    expect(screen.queryByText(/⚙ Concept/)).not.toBeInTheDocument()
  })
})
