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

const mockUseSubscriptionWithErrorHandling = vi.hoisted(() => vi.fn())
vi.mock('@/hooks', () => ({
  useSubscriptionWithErrorHandling: mockUseSubscriptionWithErrorHandling,
}))

let mockUseQueryReturn: { data: unknown; isLoading: boolean; refetch?: () => Promise<unknown> } = {
  data: undefined,
  isLoading: false,
  refetch: vi.fn().mockResolvedValue({}),
}

vi.mock('@/lib/trpc', () => ({
  trpc: {
    agent: {
      getQuestionsAsked: {
        useQuery: vi.fn((_args: unknown, _opts: unknown) => mockUseQueryReturn),
      },
    },
    onEvent: {
      useSubscription: vi.fn(),
    },
  },
}))

import { QuestionsAskedDialog } from '../QuestionsAskedDialog'

const defaultProps = {
  open: true,
  onOpenChange: vi.fn(),
  agentId: 'agent-123',
  agentName: 'test-agent',
}

describe('QuestionsAskedDialog', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    mockUseQueryReturn = {
      data: undefined,
      isLoading: false,
      refetch: vi.fn().mockResolvedValue({}),
    }
    mockUseSubscriptionWithErrorHandling.mockReturnValue({
      isConnected: false,
      isConnecting: false,
      error: null,
      reconnectAttempts: 0,
      lastEventId: null,
      reconnect: vi.fn(),
      reset: vi.fn(),
    })
  })

  it('does not render dialog content when open=false', () => {
    render(<QuestionsAskedDialog {...defaultProps} open={false} />)
    expect(screen.queryByText(/Questions Asked/)).toBeNull()
  })

  it('shows skeleton rows when loading', () => {
    mockUseQueryReturn = { data: undefined, isLoading: true, refetch: vi.fn().mockResolvedValue({}) }
    render(<QuestionsAskedDialog {...defaultProps} />)
    const skeletons = document.querySelectorAll('.animate-pulse')
    expect(skeletons.length).toBeGreaterThanOrEqual(3)
    expect(screen.queryByRole('table')).toBeNull()
  })

  it('shows "No data found" when data is empty', () => {
    mockUseQueryReturn = { data: [], isLoading: false, refetch: vi.fn().mockResolvedValue({}) }
    render(<QuestionsAskedDialog {...defaultProps} />)
    expect(screen.getByText('No data found')).toBeInTheDocument()
  })

  it('renders data rows correctly', () => {
    mockUseQueryReturn = {
      data: [
        {
          timestamp: '2026-03-06T10:00:00.000Z',
          questions: [
            { question: 'Pick a method', header: 'Method', options: [{ label: 'A', description: 'Option A' }] },
            { question: 'Pick a strategy', header: 'Strategy', options: [{ label: 'B', description: 'Option B' }] },
          ],
        },
      ],
      isLoading: false,
      refetch: vi.fn().mockResolvedValue({}),
    }
    render(<QuestionsAskedDialog {...defaultProps} />)
    expect(screen.getByText('2 questions')).toBeInTheDocument()
    expect(screen.getByText('Method')).toBeInTheDocument()
    expect(screen.queryByText('Pick a method')).toBeNull()
  })

  it('expands row to show all sub-questions on click', () => {
    mockUseQueryReturn = {
      data: [
        {
          timestamp: '2026-03-06T10:00:00.000Z',
          questions: [
            { question: 'Pick a method', header: 'Method', options: [{ label: 'A', description: 'Option A' }] },
            { question: 'Pick a strategy', header: 'Strategy', options: [{ label: 'B', description: 'Option B' }] },
          ],
        },
      ],
      isLoading: false,
      refetch: vi.fn().mockResolvedValue({}),
    }
    render(<QuestionsAskedDialog {...defaultProps} />)

    fireEvent.click(screen.getByText('2 questions').closest('tr')!)
    expect(screen.getByText('Pick a method')).toBeInTheDocument()
    expect(screen.getByText('Pick a strategy')).toBeInTheDocument()
    expect(screen.getByText('• A — Option A')).toBeInTheDocument()
  })

  it('collapses row when clicked again', () => {
    mockUseQueryReturn = {
      data: [
        {
          timestamp: '2026-03-06T10:00:00.000Z',
          questions: [
            { question: 'Pick a method', header: 'Method', options: [{ label: 'A', description: 'Option A' }] },
            { question: 'Pick a strategy', header: 'Strategy', options: [{ label: 'B', description: 'Option B' }] },
          ],
        },
      ],
      isLoading: false,
      refetch: vi.fn().mockResolvedValue({}),
    }
    render(<QuestionsAskedDialog {...defaultProps} />)

    const row = screen.getByText('2 questions').closest('tr')!
    fireEvent.click(row)
    expect(screen.getByText('Pick a method')).toBeInTheDocument()
    fireEvent.click(row)
    expect(screen.queryByText('Pick a method')).toBeNull()
  })

  it('shows 200-instance note when data length is 200', () => {
    mockUseQueryReturn = {
      data: Array(200).fill({
        timestamp: '2026-03-06T10:00:00.000Z',
        questions: [
          { question: 'Pick a method', header: 'Method', options: [] },
        ],
      }),
      isLoading: false,
      refetch: vi.fn().mockResolvedValue({}),
    }
    render(<QuestionsAskedDialog {...defaultProps} />)
    expect(screen.getByText('Showing first 200 instances.')).toBeInTheDocument()
  })

  it('shows singular "1 question" for single-question rows', () => {
    mockUseQueryReturn = {
      data: [
        {
          timestamp: '2026-03-06T10:00:00.000Z',
          questions: [
            { question: 'Only one', header: 'Single', options: [] },
          ],
        },
      ],
      isLoading: false,
      refetch: vi.fn().mockResolvedValue({}),
    }
    render(<QuestionsAskedDialog {...defaultProps} />)
    expect(screen.getByText('1 question')).toBeInTheDocument()
    expect(screen.queryByText('1 questions')).toBeNull()
  })

  describe('isAgentRunning behavior', () => {
    it('shows "Last refreshed: just now" after SSE-triggered refetch when isAgentRunning=true', async () => {
      let capturedOnData: ((event: any) => void) | undefined
      mockUseSubscriptionWithErrorHandling.mockImplementation((_getter: any, opts: any) => {
        capturedOnData = opts.onData
        return { isConnected: true, isConnecting: false, error: null, reconnectAttempts: 0, lastEventId: null, reconnect: vi.fn(), reset: vi.fn() }
      })

      const mockRefetch = vi.fn().mockResolvedValue({ data: [] })
      mockUseQueryReturn = {
        data: [],
        isLoading: false,
        refetch: mockRefetch,
      }

      render(<QuestionsAskedDialog {...defaultProps} agentId="agent-1" isAgentRunning={true} />)

      await act(async () => {
        capturedOnData?.({ data: { type: 'agent:waiting', agentId: 'agent-1' } })
      })

      await waitFor(() => {
        expect(screen.getByText(/Last refreshed: just now/)).toBeInTheDocument()
      })
    })

    it('does not show "Last refreshed" when isAgentRunning=false', () => {
      render(<QuestionsAskedDialog {...defaultProps} isAgentRunning={false} />)
      expect(screen.queryByText(/Last refreshed/)).not.toBeInTheDocument()
    })

    it('does not show "Last refreshed" when isAgentRunning is not provided', () => {
      render(<QuestionsAskedDialog {...defaultProps} />)
      expect(screen.queryByText(/Last refreshed/)).not.toBeInTheDocument()
    })

    it('subscription is enabled only when open=true and isAgentRunning=true', () => {
      render(<QuestionsAskedDialog open={false} onOpenChange={vi.fn()} agentId="agent-1" agentName="test-agent" isAgentRunning={true} />)
      expect(mockUseSubscriptionWithErrorHandling).toHaveBeenCalledWith(
        expect.any(Function),
        expect.objectContaining({ enabled: false })
      )
    })
  })
})
