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

// Mock trpc to control getAgentOutput
vi.mock('@/lib/trpc', () => ({
  trpc: {
    getAgentOutput: {
      useQuery: vi.fn(() => ({ data: [], isLoading: false })),
    },
  },
}))

// Mock @tanstack/react-router's Link
vi.mock('@tanstack/react-router', () => ({
  Link: ({ children, params }: { children: React.ReactNode; params?: Record<string, string> }) => (
    <a href={params?.initiativeId ?? '#'}>{children}</a>
  ),
}))

// Mock AgentOutputViewer
vi.mock('./AgentOutputViewer', () => ({
  AgentOutputViewer: () => <div data-testid="agent-output-viewer" />,
}))

function makeAgent(overrides?: Partial<ReturnType<typeof makeAgent>>): {
  id: string
  name: string
  status: string
  taskId: string | null
  taskName: string | null
  phaseName: string | null
  initiativeName: string | null
  initiativeId: string | null
  updatedAt: string
} {
  return {
    id: 'agent-1',
    name: 'Test Agent',
    status: 'waiting_for_input',
    taskId: 'task-1',
    taskName: 'Implement auth',
    phaseName: 'Phase 1',
    initiativeName: 'My Initiative',
    initiativeId: 'init-1',
    updatedAt: new Date().toISOString(),
    ...overrides,
  }
}

function renderPanel(
  agentOverrides?: Parameters<typeof makeAgent>[0],
  propOverrides?: {
    taskDescription?: string | null
    isLoadingContext?: boolean
    questions?: any[]
    isLoadingQuestions?: boolean
    message?: { id: string; content: string; requiresResponse: boolean } | null
  }
) {
  const agent = makeAgent(agentOverrides)
  const props = {
    taskDescription: null as string | null,
    isLoadingContext: false,
    questions: [] as any[],
    isLoadingQuestions: false,
    message: null as { id: string; content: string; requiresResponse: boolean } | null,
    questionsError: null,
    onBack: vi.fn(),
    onSubmitAnswers: vi.fn(),
    onDismissQuestions: vi.fn(),
    onDismissMessage: vi.fn(),
    isSubmitting: false,
    isDismissingQuestions: false,
    isDismissingMessage: false,
    submitError: null,
    dismissMessageError: null,
    ...propOverrides,
  }
  return render(<InboxDetailPanel agent={agent} {...props} />)
}

import * as trpcModule from '@/lib/trpc'

describe('InboxDetailPanel', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    // Default: empty output
    vi.mocked(trpcModule.trpc.getAgentOutput.useQuery).mockReturnValue({
      data: [],
      isLoading: false,
    } as any)
  })

  // -------------------------
  // Task name header tests
  // -------------------------

  it('task name header — shows taskName when set', () => {
    renderPanel({ taskName: 'Implement auth', taskId: 'some-uuid-1234' })

    expect(screen.getByText(/Task: Implement auth/)).toBeInTheDocument()
    expect(screen.queryByText(/some-uuid-1234/)).not.toBeInTheDocument()
  })

  it('task name header — falls back to taskId when taskName is null', () => {
    renderPanel({ taskName: null, taskId: 'abc-uuid' })

    expect(screen.getByText(/Task:.*abc-uuid/)).toBeInTheDocument()
  })

  it('task name header — shows em dash when both are null', () => {
    renderPanel({ taskName: null, taskId: null })

    expect(screen.getByText(/Task:.*—/)).toBeInTheDocument()
  })

  // -------------------------
  // Context panel tests
  // -------------------------

  it('context panel — loaded, with task, shows all fields', () => {
    renderPanel(
      {
        taskId: 'task-1',
        taskName: 'Impl auth',
        initiativeName: 'My Initiative',
        initiativeId: 'init-1',
        phaseName: 'Phase 1',
      },
      {
        taskDescription: 'Some description',
        isLoadingContext: false,
      }
    )

    expect(screen.getByText('My Initiative')).toBeInTheDocument()
    // Task name in context panel
    expect(screen.getAllByText(/Impl auth/).length).toBeGreaterThan(0)
    expect(screen.getByText('Some description')).toBeInTheDocument()
    expect(screen.getByText(/Phase 1/)).toBeInTheDocument()
  })

  it('context panel — truncates description longer than 300 chars', () => {
    const longDescription = 'A'.repeat(301)
    renderPanel(
      { taskId: 'task-1' },
      { taskDescription: longDescription, isLoadingContext: false }
    )

    const truncated = screen.getByText(/A+…/)
    const text = truncated.textContent ?? ''
    expect(text.endsWith('…')).toBe(true)
    expect(text.length).toBeLessThanOrEqual(301)
  })

  it('context panel — strips HTML tags from description', () => {
    renderPanel(
      { taskId: 'task-1' },
      { taskDescription: '<p>Some text</p>', isLoadingContext: false }
    )

    expect(screen.getByText('Some text')).toBeInTheDocument()
    // <p> should not appear as literal text
    expect(screen.queryByText(/<p>/)).not.toBeInTheDocument()
    // The rendered content should not contain raw HTML tags
    const container = document.querySelector('body')!
    expect(container.innerHTML).not.toContain('&lt;p&gt;')
  })

  it('context panel — shows "No task context available" when taskId is null', () => {
    renderPanel({ taskId: null }, { isLoadingContext: false })

    expect(screen.getByText('No task context available')).toBeInTheDocument()
  })

  it('context panel — shows skeleton when loading', () => {
    renderPanel({ taskId: 'task-1' }, { isLoadingContext: true })

    // Skeletons are rendered by class
    const skeletons = document.querySelectorAll('[class*="animate-pulse"]')
    expect(skeletons.length).toBeGreaterThan(0)

    // Context content NOT shown
    expect(screen.queryByText('No task context available')).not.toBeInTheDocument()
    expect(screen.queryByText(/Initiative:/)).not.toBeInTheDocument()
  })

  // -------------------------
  // Logs section tests
  // -------------------------

  it('logs section — hidden when output is empty', () => {
    vi.mocked(trpcModule.trpc.getAgentOutput.useQuery).mockReturnValue({
      data: [],
      isLoading: false,
    } as any)

    renderPanel()

    expect(screen.queryByText('Show agent logs')).not.toBeInTheDocument()
  })

  it('logs section — shows button and badge when chunks exist, clicking shows viewer', () => {
    vi.mocked(trpcModule.trpc.getAgentOutput.useQuery).mockReturnValue({
      data: [{}, {}, {}],
      isLoading: false,
    } as any)

    renderPanel()

    const button = screen.getByText('Show agent logs')
    expect(button).toBeInTheDocument()
    expect(screen.getByText('3')).toBeInTheDocument()

    fireEvent.click(button)

    expect(screen.getByTestId('agent-output-viewer')).toBeInTheDocument()
  })

  it('logs section — collapses when agent id changes', () => {
    vi.mocked(trpcModule.trpc.getAgentOutput.useQuery).mockReturnValue({
      data: [{}, {}, {}],
      isLoading: false,
    } as any)

    const { rerender } = renderPanel({ id: 'a' })

    // Open logs
    fireEvent.click(screen.getByText('Show agent logs'))
    expect(screen.getByTestId('agent-output-viewer')).toBeInTheDocument()

    // Re-render with different agent id
    const newAgent = makeAgent({ id: 'b' })
    rerender(
      <InboxDetailPanel
        agent={newAgent}
        taskDescription={null}
        isLoadingContext={false}
        questions={[]}
        isLoadingQuestions={false}
        questionsError={null}
        message={null}
        onBack={vi.fn()}
        onSubmitAnswers={vi.fn()}
        onDismissQuestions={vi.fn()}
        onDismissMessage={vi.fn()}
        isSubmitting={false}
        isDismissingQuestions={false}
        isDismissingMessage={false}
        submitError={null}
        dismissMessageError={null}
      />
    )

    // Logs should be collapsed
    expect(screen.queryByTestId('agent-output-viewer')).not.toBeInTheDocument()
    expect(screen.getByText('Show agent logs')).toBeInTheDocument()
  })
})
