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

// --- Navigation mock ---
vi.mock('next/navigation', () => ({
  useRouter: () => ({ push: vi.fn(), refresh: vi.fn() }),
}))

// --- Actions mocks ---
vi.mock('@/actions/ideas', () => ({
  createIdeaAction: vi.fn(),
  archiveIdeaAction: vi.fn(),
}))

vi.mock('@/actions/user-settings', () => ({
  updateUserSettingsAction: vi.fn().mockResolvedValue({ success: true, settings: {} }),
}))

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

// --- IdeaRowActions mock (complex component with many deps) ---
vi.mock('@/components/ideas/idea-row-actions', () => ({
  IdeaRowActions: () => <div data-testid="idea-row-actions" />,
}))

// --- DemoTooltip mock ---
vi.mock('@/components/shared/demo-tooltip', () => ({
  DemoTooltip: ({ children }: { children: React.ReactNode }) => <>{children}</>,
}))

// --- Popover mock — controlled via open prop ---
vi.mock('@/components/ui/popover', () => {
  const PopoverCtx = React.createContext<{
    open: boolean
    onOpenChange: (v: boolean) => void
  }>({ open: false, onOpenChange: () => {} })

  return {
    Popover: ({
      children,
      open,
      onOpenChange,
    }: {
      children: React.ReactNode
      open?: boolean
      onOpenChange?: (v: boolean) => void
    }) => (
      <PopoverCtx.Provider value={{ open: open ?? false, onOpenChange: onOpenChange ?? (() => {}) }}>
        {children}
      </PopoverCtx.Provider>
    ),
    PopoverTrigger: ({ render: renderEl }: { render: React.ReactElement<{ onClick?: (e: React.MouseEvent) => void }> }) => {
      const { open, onOpenChange } = React.useContext(PopoverCtx)
      return React.cloneElement(renderEl, {
        onClick: (e: React.MouseEvent) => {
          onOpenChange(!open)
          renderEl.props.onClick?.(e)
        },
      })
    },
    PopoverContent: ({ children }: { children: React.ReactNode }) => {
      const { open } = React.useContext(PopoverCtx)
      return open ? <div data-testid="popover-content">{children}</div> : null
    },
  }
})

// Import after mocks
import { useUserSettingsStore } from '@/stores/user-settings/store'
import { IdeaList } from '@/components/ideas/idea-list'
import { createIdeaAction } from '@/actions/ideas'
import type { IdeaDto } from '@/lib/idea-dto'

const PRODUCTS = [
  { id: 'prod-1', name: 'Product A', repo_url: null },
  // repo_url ingesteld zodat de optietekst gewoon "Product B" is (zonder "(geen repo)" suffix)
  { id: 'prod-2', name: 'Product B', repo_url: 'https://github.com/org/prod-b' },
]

// Minimal IdeaDto factory
function makeIdea(overrides: Partial<IdeaDto> = {}): IdeaDto {
  return {
    id: 'idea-1',
    code: 'ID-1',
    title: 'Test Idee',
    description: null,
    status: 'draft',
    product_id: null,
    product: null,
    pbi_id: null,
    pbi: null,
    secondary_products: [],
    archived: false,
    has_grill_md: false,
    has_plan_md: false,
    created_at: '2024-01-01T00:00:00.000Z',
    updated_at: '2024-01-01T00:00:00.000Z',
    ...overrides,
  }
}

const IDEAS: IdeaDto[] = [
  makeIdea({ id: 'idea-1', code: 'ID-1', title: 'Idee Concept', status: 'draft' }),
  makeIdea({ id: 'idea-2', code: 'ID-2', title: 'Idee Gegrilld', status: 'grilled' }),
  makeIdea({ id: 'idea-3', code: 'ID-3', title: 'Idee Gepland', status: 'planned' }),
]

beforeEach(() => {
  vi.clearAllMocks()
  useUserSettingsStore.getState().hydrate({}, false)
})

describe('IdeaList — filterpopover', () => {
  it('toont de "Filters"-knop in de toolbar (geen inline chip-rij)', () => {
    render(<IdeaList ideas={IDEAS} products={[]} isDemo={false} activeProductId={null} />)

    // Filters-knop aanwezig
    expect(screen.getByText('Filters')).toBeInTheDocument()

    // Status-labels zoals "Concept" mogen NIET los zichtbaar zijn zonder popover te openen
    // (anders was de oude inline chip-rij er nog)
    expect(screen.queryByRole('button', { name: 'Concept' })).not.toBeInTheDocument()
  })

  it('klik op "Filters" opent de popover en toont 11 statusopties', () => {
    render(<IdeaList ideas={IDEAS} products={[]} isDemo={false} activeProductId={null} />)

    // Popover nog niet open: content niet zichtbaar
    expect(screen.queryByTestId('popover-content')).not.toBeInTheDocument()

    fireEvent.click(screen.getByText('Filters'))

    // Content verschijnt
    expect(screen.getByTestId('popover-content')).toBeInTheDocument()

    // 11 statusopties + "Alle" = 12 buttons in de popover
    // Controleer specifiek de 11 status-labels
    const statusLabels = [
      'Concept', 'Grillen', 'Gegrilld', 'Plannen', 'Plan klaar',
      'Plan beoordelen', 'Gepland', 'Grill mislukt', 'Plan mislukt',
      'Beoordeling mislukt', 'Plan beoordeeld',
    ]
    for (const label of statusLabels) {
      expect(screen.getByRole('button', { name: label })).toBeInTheDocument()
    }
  })

  it('klik op een statuschip schrijft de status naar de store', () => {
    render(<IdeaList ideas={IDEAS} products={[]} isDemo={false} activeProductId={null} />)

    fireEvent.click(screen.getByText('Filters'))
    fireEvent.click(screen.getByRole('button', { name: 'Concept' }))

    const stored =
      useUserSettingsStore.getState().entities.settings.views?.ideasList?.filterStatuses
    expect(stored).toContain('draft')
  })

  it('gehydrateerde filter toont "Filters (1)" en filtert de tabel', () => {
    useUserSettingsStore
      .getState()
      .hydrate({ views: { ideasList: { filterStatuses: ['draft'] } } }, false)

    render(<IdeaList ideas={IDEAS} products={[]} isDemo={false} activeProductId={null} />)

    // Trigger toont het actieve filteraantal
    expect(screen.getByText('Filters (1)')).toBeInTheDocument()

    // Alleen het concept-idee is zichtbaar; de andere twee worden weggefilterd
    expect(screen.getByText('Idee Concept')).toBeInTheDocument()
    expect(screen.queryByText('Idee Gegrilld')).not.toBeInTheDocument()
    expect(screen.queryByText('Idee Gepland')).not.toBeInTheDocument()
  })

  it('"Wis filters" is disabled wanneer geen filter actief is', () => {
    render(<IdeaList ideas={IDEAS} products={[]} isDemo={false} activeProductId={null} />)

    fireEvent.click(screen.getByText('Filters'))

    const wisButton = screen.getByRole('button', { name: 'Wis filters' })
    expect(wisButton).toBeDisabled()
  })

  it('"Wis filters" is enabled en wist de filter wanneer een filter actief is', () => {
    useUserSettingsStore
      .getState()
      .hydrate({ views: { ideasList: { filterStatuses: ['draft'] } } }, false)

    render(<IdeaList ideas={IDEAS} products={[]} isDemo={false} activeProductId={null} />)

    fireEvent.click(screen.getByText('Filters (1)'))

    const wisButton = screen.getByRole('button', { name: 'Wis filters' })
    expect(wisButton).not.toBeDisabled()

    fireEvent.click(wisButton)

    const stored =
      useUserSettingsStore.getState().entities.settings.views?.ideasList?.filterStatuses
    expect(stored).toEqual([])
  })
})

describe('IdeaList — activeProductId voorvullen', () => {
  // Hulpfunctie: vind een knop op basis van gedeeltelijke tekstinhoud.
  // getByText() werkt hier betrouwbaarder dan getByRole({name}) voor knoppen
  // met SVG-icoon omdat de accessible-name-berekening van Base UI knoppen in
  // jsdom soms afwijkt van wat we verwachten.
  function clickButton(label: string) {
    const btn = Array.from(document.querySelectorAll('button')).find(
      (b) => b.textContent?.trim().includes(label)
    )
    if (!btn) throw new Error(`Knop met tekst "${label}" niet gevonden`)
    fireEvent.click(btn)
  }

  it('AC1: "Nieuw idee"-select is voorgevuld met het actieve product', async () => {
    render(
      <IdeaList ideas={[]} products={PRODUCTS} isDemo={false} activeProductId="prod-2" />
    )

    clickButton('Nieuw idee')

    // Wacht tot het formulier verschijnt; create-form-select toont "Product B" (waarde 'prod-2').
    // De toolbar-select toont "Alle producten" (waarde 'all'), zodat displayValue uniek is.
    const createFormSelect = await waitFor(() => screen.getByDisplayValue('Product B'))
    expect(createFormSelect).toHaveValue('prod-2')
  })

  it('AC2: "Nieuw idee"-select staat op leeg wanneer activeProductId null is', async () => {
    render(
      <IdeaList ideas={[]} products={PRODUCTS} isDemo={false} activeProductId={null} />
    )

    clickButton('Nieuw idee')

    // Toolbar-select toont "Alle producten"; create-form-select toont de placeholder (waarde '').
    const createFormSelect = await waitFor(() =>
      screen.getByDisplayValue('Geen product (kan later worden gekoppeld)')
    )
    expect(createFormSelect).toHaveValue('')
  })

  it('AC3: "Snel idee" stuurt product_id gelijk aan activeProductId mee', async () => {
    vi.mocked(createIdeaAction).mockResolvedValue({ data: { code: 'ID-99', id: 'idea-99' } } as never)

    render(
      <IdeaList ideas={[]} products={PRODUCTS} isDemo={false} activeProductId="prod-2" />
    )

    // Open "Snel idee"-formulier en wacht tot het verschijnt
    clickButton('Snel idee')
    await waitFor(() => screen.getByPlaceholderText('Titel *'))

    // Vul de verplichte titel in
    fireEvent.change(screen.getByPlaceholderText('Titel *'), {
      target: { value: 'Mijn snel idee' },
    })

    // Klik Opslaan — startTransition roept createIdeaAction synchroon aan
    clickButton('Opslaan')

    await waitFor(() => {
      expect(createIdeaAction).toHaveBeenCalledWith({
        title: 'Mijn snel idee',
        description: null,
        product_id: 'prod-2',
      })
    })
  })
})
