import { render, screen, fireEvent } from '@testing-library/react'
import { GanttListView } from '../GanttListView'
import type { GanttListViewProps } from '../GanttListView'
import type { GanttTask, TimelineItem } from '../types'

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function makeItem(overrides: Partial<TimelineItem> & { id: string; title: string; status: string }): TimelineItem {
  return { startDate: '2025-01-01', endDate: '2025-03-31', ...overrides }
}

function makeTask(item: TimelineItem, overrides: Partial<GanttTask> = {}): GanttTask {
  return {
    item,
    start: new Date('2025-01-01'),
    end: new Date('2025-03-31'),
    progress: 50,
    timeProgress: 30,
    depth: 0,
    hasChildren: false,
    parentId: null,
    healthStatus: 'on_track',
    ...overrides,
  }
}

const CATEGORY_COLORS: Record<string, string> = {
  product: '#3b82f6',
  team: '#a855f7',
  other: '#6b7280',
}

function defaultProps(overrides: Partial<GanttListViewProps> = {}): GanttListViewProps {
  return {
    listItems: [],
    focusedRowIndex: -1,
    categoryColors: CATEGORY_COLORS,
    handleItemClick: jest.fn(),
    ...overrides,
  }
}

// ---------------------------------------------------------------------------
// Header rendering
// ---------------------------------------------------------------------------

describe('GanttListView — header', () => {
  it('renders the Title column header', () => {
    render(<GanttListView {...defaultProps()} />)
    expect(screen.getByText('Title')).toBeInTheDocument()
  })

  it('renders the Status column header', () => {
    render(<GanttListView {...defaultProps()} />)
    expect(screen.getByText('Status')).toBeInTheDocument()
  })

  it('renders the Category column header', () => {
    render(<GanttListView {...defaultProps()} />)
    expect(screen.getByText('Category')).toBeInTheDocument()
  })

  it('renders the Dates column header', () => {
    render(<GanttListView {...defaultProps()} />)
    expect(screen.getByText('Dates')).toBeInTheDocument()
  })

  it('renders the Progress column header', () => {
    render(<GanttListView {...defaultProps()} />)
    expect(screen.getByText('Progress')).toBeInTheDocument()
  })
})

// ---------------------------------------------------------------------------
// Empty state
// ---------------------------------------------------------------------------

describe('GanttListView — empty state', () => {
  it('renders only the header row when listItems is empty', () => {
    const { container } = render(<GanttListView {...defaultProps()} />)
    expect(container.querySelectorAll('.gantt-list-row')).toHaveLength(0)
  })
})

// ---------------------------------------------------------------------------
// Row rendering
// ---------------------------------------------------------------------------

describe('GanttListView — row rendering', () => {
  it('renders a row for each task', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Alpha', status: 'in_progress' })),
      makeTask(makeItem({ id: 'b', title: 'Beta', status: 'completed' })),
      makeTask(makeItem({ id: 'c', title: 'Gamma', status: 'not_started' })),
    ]
    const { container } = render(<GanttListView {...defaultProps({ listItems })} />)
    expect(container.querySelectorAll('.gantt-list-row')).toHaveLength(3)
  })

  it('renders each task title in the list', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Alpha Task', status: 'in_progress' })),
      makeTask(makeItem({ id: 'b', title: 'Beta Task', status: 'completed' })),
    ]
    render(<GanttListView {...defaultProps({ listItems })} />)
    expect(screen.getByText('Alpha Task')).toBeInTheDocument()
    expect(screen.getByText('Beta Task')).toBeInTheDocument()
  })

  it('renders a status badge with the task status (underscores replaced with spaces)', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Task A', status: 'in_progress' })),
      makeTask(makeItem({ id: 'b', title: 'Task B', status: 'not_started' })),
    ]
    render(<GanttListView {...defaultProps({ listItems })} />)
    expect(screen.getByText('in progress')).toBeInTheDocument()
    expect(screen.getByText('not started')).toBeInTheDocument()
  })

  it('renders a category badge when the task item has a category', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Task A', status: 'in_progress', category: 'product' })),
    ]
    render(<GanttListView {...defaultProps({ listItems })} />)
    expect(screen.getByText('product')).toBeInTheDocument()
  })

  it('does not render a category badge when item has no category', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Task A', status: 'in_progress' })),
    ]
    const { container } = render(<GanttListView {...defaultProps({ listItems })} />)
    expect(container.querySelector('.gantt-category-badge')).not.toBeInTheDocument()
  })

  it('renders a progress percentage text', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Task A', status: 'in_progress' }), { progress: 75 }),
    ]
    render(<GanttListView {...defaultProps({ listItems })} />)
    expect(screen.getByText('75%')).toBeInTheDocument()
  })

  it('renders 0% progress correctly', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Task A', status: 'not_started' }), { progress: 0 }),
    ]
    render(<GanttListView {...defaultProps({ listItems })} />)
    expect(screen.getByText('0%')).toBeInTheDocument()
  })

  it('renders 100% progress correctly', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Task A', status: 'completed' }), { progress: 100 }),
    ]
    render(<GanttListView {...defaultProps({ listItems })} />)
    expect(screen.getByText('100%')).toBeInTheDocument()
  })

  it('renders formatted date range in the Dates column', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Task A', status: 'in_progress' }), {
        // Use local-time constructor to avoid UTC→local timezone offset shifting the day
        start: new Date(2025, 0, 15),  // Jan 15 2025 local
        end: new Date(2025, 3, 20),    // Apr 20 2025 local
      }),
    ]
    const { container } = render(<GanttListView {...defaultProps({ listItems })} />)
    // The dates cell contains the full range as its textContent
    const datesCell = container.querySelector('.gantt-list-col-dates:not(.gantt-list-header span)')
    // Find the data row's dates cell (second .gantt-list-col-dates element)
    const datesCells = container.querySelectorAll('.gantt-list-col-dates')
    // datesCells[0] is the header "Dates", datesCells[1] is the data row cell
    const dataCell = datesCells[1] as HTMLElement
    expect(dataCell.textContent).toMatch(/Jan 15/)
    expect(dataCell.textContent).toMatch(/Apr 20/)
  })
})

// ---------------------------------------------------------------------------
// Focus state
// ---------------------------------------------------------------------------

describe('GanttListView — focus state', () => {
  it('applies gantt-row-focused class to the focused row index', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Alpha', status: 'not_started' })),
      makeTask(makeItem({ id: 'b', title: 'Beta', status: 'in_progress' })),
    ]
    const { container } = render(
      <GanttListView {...defaultProps({ listItems, focusedRowIndex: 1 })} />
    )
    const rows = container.querySelectorAll('.gantt-list-row')
    expect(rows[0]).not.toHaveClass('gantt-row-focused')
    expect(rows[1]).toHaveClass('gantt-row-focused')
  })

  it('does not apply gantt-row-focused when focusedRowIndex is -1', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Alpha', status: 'not_started' })),
    ]
    const { container } = render(
      <GanttListView {...defaultProps({ listItems, focusedRowIndex: -1 })} />
    )
    expect(container.querySelector('.gantt-row-focused')).not.toBeInTheDocument()
  })
})

// ---------------------------------------------------------------------------
// Item click
// ---------------------------------------------------------------------------

describe('GanttListView — item click', () => {
  it('calls handleItemClick when a row is clicked', () => {
    const handleItemClick = jest.fn()
    const item = makeItem({ id: 'a', title: 'Clickable Task', status: 'in_progress' })
    const listItems = [makeTask(item)]
    render(<GanttListView {...defaultProps({ listItems, handleItemClick })} />)
    fireEvent.click(screen.getByText('Clickable Task'))
    expect(handleItemClick).toHaveBeenCalledWith(item)
  })

  it('calls handleItemClick with the correct item when multiple rows exist', () => {
    const handleItemClick = jest.fn()
    const itemA = makeItem({ id: 'a', title: 'Task A', status: 'in_progress' })
    const itemB = makeItem({ id: 'b', title: 'Task B', status: 'completed' })
    const listItems = [makeTask(itemA), makeTask(itemB)]
    render(<GanttListView {...defaultProps({ listItems, handleItemClick })} />)
    fireEvent.click(screen.getByText('Task B'))
    expect(handleItemClick).toHaveBeenCalledWith(itemB)
    expect(handleItemClick).toHaveBeenCalledTimes(1)
  })
})

// ---------------------------------------------------------------------------
// Depth indentation
// ---------------------------------------------------------------------------

describe('GanttListView — depth indentation', () => {
  it('renders an indent spacer for child tasks (depth > 0)', () => {
    const listItems = [
      makeTask(makeItem({ id: 'child', title: 'Child Task', status: 'in_progress' }), { depth: 1 }),
    ]
    const { container } = render(<GanttListView {...defaultProps({ listItems })} />)
    // The indent span has inline style with a calculated width
    const row = container.querySelector('.gantt-list-row')
    const indentSpan = row?.querySelector('span[style]')
    expect(indentSpan).toBeInTheDocument()
  })

  it('does not render an indent spacer for root tasks (depth 0)', () => {
    const listItems = [
      makeTask(makeItem({ id: 'root', title: 'Root Task', status: 'in_progress' }), { depth: 0 }),
    ]
    const { container } = render(<GanttListView {...defaultProps({ listItems })} />)
    const row = container.querySelector('.gantt-list-row')
    // At depth 0, no inline-block span is injected
    const titleCell = row?.querySelector('.gantt-list-col-title')
    // Check that no child span with display:inline-block exists
    const indentSpans = titleCell?.querySelectorAll('span[style]') ?? []
    expect(indentSpans).toHaveLength(0)
  })
})

// ---------------------------------------------------------------------------
// Progress bar color
// ---------------------------------------------------------------------------

describe('GanttListView — progress bar', () => {
  it('renders the progress fill bar', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Task A', status: 'in_progress' }), { progress: 60 }),
    ]
    const { container } = render(<GanttListView {...defaultProps({ listItems })} />)
    const fill = container.querySelector('.gantt-list-progress-fill') as HTMLElement | null
    expect(fill).toBeInTheDocument()
    expect(fill?.style.width).toBe('60%')
  })

  it('uses the on_track health color for the progress fill when healthStatus is on_track', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Task A', status: 'in_progress' }), {
        progress: 50,
        healthStatus: 'on_track',
      }),
    ]
    const { container } = render(<GanttListView {...defaultProps({ listItems })} />)
    const fill = container.querySelector('.gantt-list-progress-fill') as HTMLElement | null
    // on_track color is #22c55e
    expect(fill?.style.backgroundColor).toBe('rgb(34, 197, 94)')
  })

  it('uses the at_risk health color when healthStatus is at_risk', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Task A', status: 'in_progress' }), {
        progress: 20,
        healthStatus: 'at_risk',
      }),
    ]
    const { container } = render(<GanttListView {...defaultProps({ listItems })} />)
    const fill = container.querySelector('.gantt-list-progress-fill') as HTMLElement | null
    // at_risk color is #eab308
    expect(fill?.style.backgroundColor).toBe('rgb(234, 179, 8)')
  })

  it('uses the blocked health color when healthStatus is blocked', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Task A', status: 'blocked' }), {
        progress: 10,
        healthStatus: 'blocked',
      }),
    ]
    const { container } = render(<GanttListView {...defaultProps({ listItems })} />)
    const fill = container.querySelector('.gantt-list-progress-fill') as HTMLElement | null
    // blocked color is #ef4444
    expect(fill?.style.backgroundColor).toBe('rgb(239, 68, 68)')
  })
})

// ---------------------------------------------------------------------------
// Category color fallback
// ---------------------------------------------------------------------------

describe('GanttListView — category color fallback', () => {
  it('uses the other fallback color for unknown categories', () => {
    const listItems = [
      makeTask(makeItem({ id: 'a', title: 'Task A', status: 'in_progress', category: 'unknown_cat' })),
    ]
    const { container } = render(<GanttListView {...defaultProps({ listItems })} />)
    const badge = container.querySelector('.gantt-category-badge') as HTMLElement | null
    expect(badge).toBeInTheDocument()
    // '#6b7280' in rgb
    expect(badge?.style.backgroundColor).toBe('rgb(107, 114, 128)')
  })
})
