// @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: {
    conversation: {
      getByFromAgent: {
        useQuery: vi.fn((_args: unknown, _opts: unknown) => mockUseQueryReturn),
      },
    },
    onEvent: {
      useSubscription: vi.fn(),
    },
  },
}))

import { InterAgentMessagesDialog } from '../InterAgentMessagesDialog'

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

describe('InterAgentMessagesDialog', () => {
  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(<InterAgentMessagesDialog {...defaultProps} open={false} />)
    expect(screen.queryByText(/Inter-Agent Messages/)).toBeNull()
  })

  it('shows skeleton rows when loading', () => {
    mockUseQueryReturn = { data: undefined, isLoading: true, refetch: vi.fn().mockResolvedValue({}) }
    render(<InterAgentMessagesDialog {...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(<InterAgentMessagesDialog {...defaultProps} />)
    expect(screen.getByText('No data found')).toBeInTheDocument()
  })

  it('renders data rows for answered conversation', () => {
    mockUseQueryReturn = {
      data: [
        {
          id: 'c1',
          timestamp: '2026-03-06T10:00:00.000Z',
          toAgentName: 'target-agent',
          toAgentId: 'agent-2',
          question: 'What is the export path?',
          answer: 'It is src/api/index.ts',
          status: 'answered',
          taskId: null,
          phaseId: null,
        },
      ],
      isLoading: false,
      refetch: vi.fn().mockResolvedValue({}),
    }
    render(<InterAgentMessagesDialog {...defaultProps} />)
    expect(screen.getByText('target-agent')).toBeInTheDocument()
    expect(screen.getByText('answered')).toBeInTheDocument()
    expect(screen.queryByText('What is the export path?')).toBeNull()
  })

  it('expands answered row to show question and answer', () => {
    mockUseQueryReturn = {
      data: [
        {
          id: 'c1',
          timestamp: '2026-03-06T10:00:00.000Z',
          toAgentName: 'target-agent',
          toAgentId: 'agent-2',
          question: 'What is the export path?',
          answer: 'It is src/api/index.ts',
          status: 'answered',
          taskId: null,
          phaseId: null,
        },
      ],
      isLoading: false,
      refetch: vi.fn().mockResolvedValue({}),
    }
    render(<InterAgentMessagesDialog {...defaultProps} />)

    fireEvent.click(screen.getByText('target-agent').closest('tr')!)
    expect(screen.getByText('What is the export path?')).toBeInTheDocument()
    expect(screen.getByText('It is src/api/index.ts')).toBeInTheDocument()
    expect(screen.queryByText('No answer yet')).toBeNull()
  })

  it('expands pending row to show question and "No answer yet"', () => {
    mockUseQueryReturn = {
      data: [
        {
          id: 'c2',
          timestamp: '2026-03-06T10:00:00.000Z',
          toAgentName: 'target-agent',
          toAgentId: 'agent-2',
          question: 'What is the export path?',
          answer: null,
          status: 'pending',
          taskId: null,
          phaseId: null,
        },
      ],
      isLoading: false,
      refetch: vi.fn().mockResolvedValue({}),
    }
    render(<InterAgentMessagesDialog {...defaultProps} />)

    fireEvent.click(screen.getByText('target-agent').closest('tr')!)
    expect(screen.getByText('What is the export path?')).toBeInTheDocument()
    expect(screen.getByText('No answer yet')).toBeInTheDocument()
    expect(screen.queryByText('It is src/api/index.ts')).toBeNull()
  })

  it('collapses row when clicked again', () => {
    mockUseQueryReturn = {
      data: [
        {
          id: 'c1',
          timestamp: '2026-03-06T10:00:00.000Z',
          toAgentName: 'target-agent',
          toAgentId: 'agent-2',
          question: 'What is the export path?',
          answer: 'It is src/api/index.ts',
          status: 'answered',
          taskId: null,
          phaseId: null,
        },
      ],
      isLoading: false,
      refetch: vi.fn().mockResolvedValue({}),
    }
    render(<InterAgentMessagesDialog {...defaultProps} />)

    const row = screen.getByText('target-agent').closest('tr')!
    fireEvent.click(row)
    expect(screen.getByText('What is the export path?')).toBeInTheDocument()
    fireEvent.click(row)
    expect(screen.queryByText('What is the export path?')).toBeNull()
  })

  it('shows 200-instance note when data length is 200', () => {
    mockUseQueryReturn = {
      data: Array(200).fill({
        id: 'c1',
        timestamp: '2026-03-06T10:00:00.000Z',
        toAgentName: 'target-agent',
        toAgentId: 'agent-2',
        question: 'What is the export path?',
        answer: null,
        status: 'pending',
        taskId: null,
        phaseId: null,
      }),
      isLoading: false,
      refetch: vi.fn().mockResolvedValue({}),
    }
    render(<InterAgentMessagesDialog {...defaultProps} />)
    expect(screen.getByText('Showing first 200 instances.')).toBeInTheDocument()
  })

  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(<InterAgentMessagesDialog {...defaultProps} agentId="agent-1" isAgentRunning={true} />)

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

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

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

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

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