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

import { SubagentSpawnsDialog } from '../SubagentSpawnsDialog'

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

describe('SubagentSpawnsDialog', () => {
  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(<SubagentSpawnsDialog {...defaultProps} open={false} />)
    expect(screen.queryByText(/Subagent Spawns/)).toBeNull()
  })

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

  it('renders data rows correctly', () => {
    mockUseQueryReturn = {
      data: [
        {
          timestamp: '2026-03-06T10:00:00.000Z',
          description: 'my task',
          promptPreview: 'hello',
          fullPrompt: 'hello world full',
        },
      ],
      isLoading: false,
      refetch: vi.fn().mockResolvedValue({}),
    }
    render(<SubagentSpawnsDialog {...defaultProps} />)
    expect(screen.getByText('my task')).toBeInTheDocument()
    expect(screen.getByText('hello')).toBeInTheDocument()
    expect(screen.queryByText('hello world full')).toBeNull()
  })

  it('expands and collapses row on click', () => {
    mockUseQueryReturn = {
      data: [
        {
          timestamp: '2026-03-06T10:00:00.000Z',
          description: 'my task',
          promptPreview: 'hello',
          fullPrompt: 'hello world full',
        },
      ],
      isLoading: false,
      refetch: vi.fn().mockResolvedValue({}),
    }
    render(<SubagentSpawnsDialog {...defaultProps} />)

    // Click the row — should expand
    fireEvent.click(screen.getByText('my task').closest('tr')!)
    expect(screen.getByText('hello world full')).toBeInTheDocument()

    // Click again — should collapse
    fireEvent.click(screen.getByText('my task').closest('tr')!)
    expect(screen.queryByText('hello world full')).toBeNull()
  })

  it('shows ellipsis suffix when fullPrompt is longer than promptPreview', () => {
    const fullPrompt = 'A'.repeat(201)
    const promptPreview = fullPrompt.slice(0, 200)
    mockUseQueryReturn = {
      data: [
        {
          timestamp: '2026-03-06T10:00:00.000Z',
          description: 'truncated task',
          promptPreview,
          fullPrompt,
        },
      ],
      isLoading: false,
      refetch: vi.fn().mockResolvedValue({}),
    }
    render(<SubagentSpawnsDialog {...defaultProps} />)
    expect(screen.getByText('…')).toBeInTheDocument()
  })

  it('shows 200-instance note when data length is 200', () => {
    mockUseQueryReturn = {
      data: Array(200).fill({
        timestamp: '2026-03-06T10:00:00.000Z',
        description: 'task',
        promptPreview: 'prompt',
        fullPrompt: 'full prompt',
      }),
      isLoading: false,
      refetch: vi.fn().mockResolvedValue({}),
    }
    render(<SubagentSpawnsDialog {...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(<SubagentSpawnsDialog {...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(<SubagentSpawnsDialog {...defaultProps} isAgentRunning={false} />)
      expect(screen.queryByText(/Last refreshed/)).not.toBeInTheDocument()
    })

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

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