import { render, screen, fireEvent } from '@testing-library/react'
import { GanttBoardView } from '../GanttBoardView'
import type { GanttBoardViewProps } from '../GanttBoardView'
import type { 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 }
}

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

function defaultProps(overrides: Partial<GanttBoardViewProps> = {}): GanttBoardViewProps {
  return {
    boardColumns: [],
    boardDragItem: null,
    setBoardDragItem: jest.fn(),
    onStatusChange: undefined,
    categoryColors: CATEGORY_COLORS,
    handleItemClick: jest.fn(),
    ...overrides,
  }
}

// ---------------------------------------------------------------------------
// Column rendering
// ---------------------------------------------------------------------------

describe('GanttBoardView — column rendering', () => {
  it('renders nothing when boardColumns is empty', () => {
    const { container } = render(<GanttBoardView {...defaultProps()} />)
    // The board wrapper div is rendered but contains no column children
    expect(container.querySelector('.gantt-board-column')).not.toBeInTheDocument()
  })

  it('renders one column per status', () => {
    const columns = [
      { status: 'not_started', items: [] },
      { status: 'in_progress', items: [] },
      { status: 'completed', items: [] },
    ]
    const { container } = render(<GanttBoardView {...defaultProps({ boardColumns: columns })} />)
    expect(container.querySelectorAll('.gantt-board-column')).toHaveLength(3)
  })

  it('renders a status badge in each column header', () => {
    const columns = [
      { status: 'not_started', items: [] },
      { status: 'in_progress', items: [] },
    ]
    render(<GanttBoardView {...defaultProps({ boardColumns: columns })} />)
    // Underscores are replaced with spaces in the badge
    expect(screen.getByText('not started')).toBeInTheDocument()
    expect(screen.getByText('in progress')).toBeInTheDocument()
  })

  it('displays the item count in each column header', () => {
    const columns = [
      { status: 'not_started', items: [makeItem({ id: 'a', title: 'Task A', status: 'not_started' })] },
      { status: 'in_progress', items: [] },
    ]
    render(<GanttBoardView {...defaultProps({ boardColumns: columns })} />)
    // Count badges: '1' for the first column, '0' for the second
    const counts = screen.getAllByText('1')
    expect(counts.length).toBeGreaterThanOrEqual(1)
    expect(screen.getByText('0')).toBeInTheDocument()
  })
})

// ---------------------------------------------------------------------------
// Card rendering
// ---------------------------------------------------------------------------

describe('GanttBoardView — card rendering', () => {
  it('renders a card for each item in a column', () => {
    const columns = [
      {
        status: 'in_progress',
        items: [
          makeItem({ id: 'a', title: 'Alpha Task', status: 'in_progress' }),
          makeItem({ id: 'b', title: 'Beta Task', status: 'in_progress' }),
        ],
      },
    ]
    render(<GanttBoardView {...defaultProps({ boardColumns: columns })} />)
    expect(screen.getByText('Alpha Task')).toBeInTheDocument()
    expect(screen.getByText('Beta Task')).toBeInTheDocument()
  })

  it('renders a category badge on cards that have a category', () => {
    const columns = [
      {
        status: 'in_progress',
        items: [makeItem({ id: 'a', title: 'Task A', status: 'in_progress', category: 'product' })],
      },
    ]
    render(<GanttBoardView {...defaultProps({ boardColumns: columns })} />)
    expect(screen.getByText('product')).toBeInTheDocument()
  })

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

  it('renders the end date on a card when the item has an endDate', () => {
    // Use local-time ISO string to avoid UTC→local timezone shift
    const columns = [
      {
        status: 'in_progress',
        items: [makeItem({ id: 'a', title: 'Task A', status: 'in_progress', endDate: '2025-03-15T00:00:00' })],
      },
    ]
    render(<GanttBoardView {...defaultProps({ boardColumns: columns })} />)
    // date-fns format(new Date('2025-03-15T00:00:00'), 'MMM d') === 'Mar 15'
    expect(screen.getByText('Mar 15')).toBeInTheDocument()
  })

  it('does not render an end date when the item has no endDate', () => {
    const columns = [
      {
        status: 'in_progress',
        items: [{ id: 'a', title: 'No Date Task', status: 'in_progress' }],
      },
    ]
    const { container } = render(<GanttBoardView {...defaultProps({ boardColumns: columns })} />)
    expect(container.querySelector('.gantt-board-card-date')).not.toBeInTheDocument()
  })

  it('uses the fallback "other" color when the item category is not in categoryColors', () => {
    const columns = [
      {
        status: 'in_progress',
        items: [makeItem({ id: 'a', title: 'Task A', status: 'in_progress', category: 'unknown' })],
      },
    ]
    const { container } = render(<GanttBoardView {...defaultProps({ boardColumns: columns })} />)
    const badge = container.querySelector('.gantt-category-badge') as HTMLElement | null
    expect(badge).toBeInTheDocument()
    expect(badge?.style.backgroundColor).toBe('rgb(107, 114, 128)') // #6b7280 in rgb
  })
})

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

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

  it('calls handleItemClick with the correct item when multiple cards are present', () => {
    const handleItemClick = jest.fn()
    const itemA = makeItem({ id: 'a', title: 'Task A', status: 'in_progress' })
    const itemB = makeItem({ id: 'b', title: 'Task B', status: 'in_progress' })
    const columns = [{ status: 'in_progress', items: [itemA, itemB] }]
    render(<GanttBoardView {...defaultProps({ boardColumns: columns, handleItemClick })} />)
    fireEvent.click(screen.getByText('Task B'))
    expect(handleItemClick).toHaveBeenCalledWith(itemB)
  })
})

// ---------------------------------------------------------------------------
// Drag and drop
// ---------------------------------------------------------------------------

describe('GanttBoardView — drag and drop', () => {
  it('sets boardDragItem when drag starts on a card', () => {
    const setBoardDragItem = jest.fn()
    const onStatusChange = jest.fn()
    const item = makeItem({ id: 'a', title: 'Draggable', status: 'not_started' })
    const columns = [{ status: 'not_started', items: [item] }]
    const { container } = render(
      <GanttBoardView
        {...defaultProps({ boardColumns: columns, setBoardDragItem, onStatusChange })}
      />
    )
    const card = container.querySelector('.gantt-board-card') as HTMLElement
    fireEvent.dragStart(card)
    expect(setBoardDragItem).toHaveBeenCalledWith('a')
  })

  it('clears boardDragItem when drag ends', () => {
    const setBoardDragItem = jest.fn()
    const onStatusChange = jest.fn()
    const item = makeItem({ id: 'a', title: 'Draggable', status: 'not_started' })
    const columns = [{ status: 'not_started', items: [item] }]
    const { container } = render(
      <GanttBoardView
        {...defaultProps({ boardColumns: columns, setBoardDragItem, onStatusChange })}
      />
    )
    const card = container.querySelector('.gantt-board-card') as HTMLElement
    fireEvent.dragEnd(card)
    expect(setBoardDragItem).toHaveBeenCalledWith(null)
  })

  it('calls onStatusChange with the new status on drop', () => {
    const setBoardDragItem = jest.fn()
    const onStatusChange = jest.fn()
    const item = makeItem({ id: 'a', title: 'Draggable', status: 'not_started' })
    const columns = [
      { status: 'not_started', items: [item] },
      { status: 'completed', items: [] },
    ]
    const { container } = render(
      <GanttBoardView
        {...defaultProps({ boardColumns: columns, boardDragItem: 'a', setBoardDragItem, onStatusChange })}
      />
    )
    const targetColumn = container.querySelectorAll('.gantt-board-column')[1] as HTMLElement
    fireEvent.drop(targetColumn)
    expect(onStatusChange).toHaveBeenCalledWith('a', 'completed')
  })

  it('does not call onStatusChange when onStatusChange is not provided', () => {
    const setBoardDragItem = jest.fn()
    const item = makeItem({ id: 'a', title: 'Draggable', status: 'not_started' })
    const columns = [
      { status: 'not_started', items: [item] },
      { status: 'completed', items: [] },
    ]
    // Should not throw even without onStatusChange
    const { container } = render(
      <GanttBoardView
        {...defaultProps({
          boardColumns: columns,
          boardDragItem: 'a',
          setBoardDragItem,
          onStatusChange: undefined,
        })}
      />
    )
    const targetColumn = container.querySelectorAll('.gantt-board-column')[1] as HTMLElement
    expect(() => fireEvent.drop(targetColumn)).not.toThrow()
    expect(setBoardDragItem).toHaveBeenCalledWith(null)
  })

  it('cards are not draggable when onStatusChange is undefined', () => {
    const item = makeItem({ id: 'a', title: 'Static', status: 'not_started' })
    const columns = [{ status: 'not_started', items: [item] }]
    const { container } = render(
      <GanttBoardView {...defaultProps({ boardColumns: columns, onStatusChange: undefined })} />
    )
    const card = container.querySelector('.gantt-board-card') as HTMLElement
    // draggable attribute should be false (falsy) when onStatusChange is absent
    expect(card.draggable).toBe(false)
  })

  it('cards are draggable when onStatusChange is provided', () => {
    const onStatusChange = jest.fn()
    const item = makeItem({ id: 'a', title: 'Draggable', status: 'not_started' })
    const columns = [{ status: 'not_started', items: [item] }]
    const { container } = render(
      <GanttBoardView {...defaultProps({ boardColumns: columns, onStatusChange })} />
    )
    const card = container.querySelector('.gantt-board-card') as HTMLElement
    expect(card.draggable).toBe(true)
  })
})

// ---------------------------------------------------------------------------
// Drag-over visual state
// ---------------------------------------------------------------------------

describe('GanttBoardView — drop-target styling', () => {
  it('applies gantt-board-drop-target class to all columns when boardDragItem is set', () => {
    const columns = [
      { status: 'not_started', items: [] },
      { status: 'completed', items: [] },
    ]
    const { container } = render(
      <GanttBoardView {...defaultProps({ boardColumns: columns, boardDragItem: 'some-id' })} />
    )
    const dropTargets = container.querySelectorAll('.gantt-board-drop-target')
    expect(dropTargets).toHaveLength(2)
  })

  it('does not apply gantt-board-drop-target when boardDragItem is null', () => {
    const columns = [{ status: 'not_started', items: [] }]
    const { container } = render(
      <GanttBoardView {...defaultProps({ boardColumns: columns, boardDragItem: null })} />
    )
    expect(container.querySelector('.gantt-board-drop-target')).not.toBeInTheDocument()
  })
})
