import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { MemoryRouter } from 'react-router'
import { TaskList } from './TaskList'
import type { Task } from '~/types/task'
import { TaskStatus } from '~/types/task'
import { useTasks } from '~/hooks/useTasks'

// Mock the useTasks hook
vi.mock('~/hooks/useTasks')
const mockUseTasks = useTasks as unknown as ReturnType<typeof vi.fn>

// Sample task data for testing
const mockTasks: Task[] = [
  {
    id: '1',
    title: 'Alpha Task',
    description: 'First task description',
    status: TaskStatus.Todo,
    created_at: '2023-01-01T00:00:00Z',
    updated_at: '2023-01-01T00:00:00Z',
    completed_at: null,
  },
  {
    id: '2',
    title: 'Beta Task',
    description: 'Second task description',
    status: TaskStatus.Done,
    created_at: '2023-01-02T00:00:00Z',
    updated_at: '2023-01-02T00:00:00Z',
    completed_at: '2023-01-02T01:00:00Z',
  },
  {
    id: '3',
    title: 'Charlie Task',
    description: null,
    status: TaskStatus.Backlog,
    created_at: '2023-01-03T00:00:00Z',
    updated_at: '2023-01-03T00:00:00Z',
    completed_at: null,
  },
]

const defaultMockUseTasks = {
  tasks: mockTasks,
  loading: false,
  error: null,
  lastFetch: new Date(),
  fetchTasks: vi.fn(),
  createTask: vi.fn(),
  refreshTasks: vi.fn(),
  deleteTask: vi.fn().mockResolvedValue(true),
  getTaskById: vi.fn(),
  filterTasksByStatus: vi.fn(),
  clearError: vi.fn(),
}

const renderTaskList = (initialTasks?: Task[]) => {
  return render(
    <MemoryRouter>
      <TaskList initialTasks={initialTasks} />
    </MemoryRouter>
  )
}

describe('TaskList Sorting Functionality', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    mockUseTasks.mockReturnValue(defaultMockUseTasks)
  })

  afterEach(() => {
    vi.restoreAllMocks()
  })

  describe('Default Sorting', () => {
    it('should default to created_desc sorting (newest first)', () => {
      renderTaskList()

      // Tasks should be ordered by creation date descending (newest first)
      const taskRows = screen.getAllByRole('row')
      // Skip header row (index 0)
      const firstTaskRow = taskRows[1]
      const secondTaskRow = taskRows[2]
      const thirdTaskRow = taskRows[3]

      // Charlie Task (2023-01-03) should be first
      expect(firstTaskRow).toHaveTextContent('Charlie Task')
      // Beta Task (2023-01-02) should be second
      expect(secondTaskRow).toHaveTextContent('Beta Task')
      // Alpha Task (2023-01-01) should be third
      expect(thirdTaskRow).toHaveTextContent('Alpha Task')
    })

    it('should show correct sort indicator for created column by default', () => {
      renderTaskList()

      const createdHeader = screen.getByRole('button', { name: /created/i })
      expect(createdHeader).toHaveClass('Mui-active')

      // Should have descending indicator (direction class)
      expect(createdHeader).toHaveClass('MuiTableSortLabel-directionDesc')
    })
  })

  describe('Title Column Sorting', () => {
    it('should sort by title ascending when clicked first time', async () => {
      renderTaskList()

      const titleHeader = screen.getByRole('button', { name: /title/i })
      fireEvent.click(titleHeader)

      await waitFor(() => {
        const taskRows = screen.getAllByRole('row')
        // Skip header row
        const firstTaskRow = taskRows[1]
        const secondTaskRow = taskRows[2]
        const thirdTaskRow = taskRows[3]

        // Should be in alphabetical order
        expect(firstTaskRow).toHaveTextContent('Alpha Task')
        expect(secondTaskRow).toHaveTextContent('Beta Task')
        expect(thirdTaskRow).toHaveTextContent('Charlie Task')
      })
    })

    it('should sort by title descending when clicked second time', async () => {
      renderTaskList()

      const titleHeader = screen.getByRole('button', { name: /title/i })

      // First click - ascending
      fireEvent.click(titleHeader)

      // Second click - descending
      fireEvent.click(titleHeader)

      await waitFor(() => {
        const taskRows = screen.getAllByRole('row')
        const firstTaskRow = taskRows[1]
        const secondTaskRow = taskRows[2]
        const thirdTaskRow = taskRows[3]

        // Should be in reverse alphabetical order
        expect(firstTaskRow).toHaveTextContent('Charlie Task')
        expect(secondTaskRow).toHaveTextContent('Beta Task')
        expect(thirdTaskRow).toHaveTextContent('Alpha Task')
      })
    })

    it('should show correct sort indicators for title column', async () => {
      renderTaskList()

      const titleHeader = screen.getByRole('button', { name: /title/i })

      // Initially not active
      expect(titleHeader).not.toHaveClass('Mui-active')

      // First click - ascending
      fireEvent.click(titleHeader)

      await waitFor(() => {
        expect(titleHeader).toHaveClass('Mui-active')
        expect(titleHeader).toHaveClass('MuiTableSortLabel-directionAsc')
      })

      // Second click - descending
      fireEvent.click(titleHeader)

      await waitFor(() => {
        expect(titleHeader).toHaveClass('Mui-active')
        expect(titleHeader).toHaveClass('MuiTableSortLabel-directionDesc')
      })
    })
  })

  describe('Status Column Sorting', () => {
    it('should sort by status priority (Todo, Backlog, Done) when clicked', async () => {
      renderTaskList()

      const statusHeader = screen.getByRole('button', { name: /status/i })
      fireEvent.click(statusHeader)

      await waitFor(() => {
        const taskRows = screen.getAllByRole('row')
        const firstTaskRow = taskRows[1]
        const secondTaskRow = taskRows[2]
        const thirdTaskRow = taskRows[3]

        // Should be ordered by status priority
        expect(firstTaskRow).toHaveTextContent('Alpha Task') // Todo
        expect(secondTaskRow).toHaveTextContent('Charlie Task') // Backlog
        expect(thirdTaskRow).toHaveTextContent('Beta Task') // Done
      })
    })

    it('should show correct sort indicator for status column', async () => {
      renderTaskList()

      const statusHeader = screen.getByRole('button', { name: /status/i })

      // Initially not active
      expect(statusHeader).not.toHaveClass('Mui-active')

      fireEvent.click(statusHeader)

      await waitFor(() => {
        expect(statusHeader).toHaveClass('Mui-active')
        expect(statusHeader).toHaveClass('MuiTableSortLabel-directionAsc')
      })
    })
  })

  describe('Created Column Sorting', () => {
    it('should toggle between ascending and descending when clicked', async () => {
      renderTaskList()

      const createdHeader = screen.getByRole('button', { name: /created/i })

      // First click should change to ascending (oldest first)
      fireEvent.click(createdHeader)

      await waitFor(() => {
        const taskRows = screen.getAllByRole('row')
        const firstTaskRow = taskRows[1]
        const thirdTaskRow = taskRows[3]

        expect(firstTaskRow).toHaveTextContent('Alpha Task') // 2023-01-01
        expect(thirdTaskRow).toHaveTextContent('Charlie Task') // 2023-01-03
      })

      // Second click should change back to descending (newest first)
      fireEvent.click(createdHeader)

      await waitFor(() => {
        const taskRows = screen.getAllByRole('row')
        const firstTaskRow = taskRows[1]
        const thirdTaskRow = taskRows[3]

        expect(firstTaskRow).toHaveTextContent('Charlie Task') // 2023-01-03
        expect(thirdTaskRow).toHaveTextContent('Alpha Task') // 2023-01-01
      })
    })
  })

  describe('Sort Persistence', () => {
    it('should maintain sort order after clicking different headers', async () => {
      renderTaskList()

      // Sort by title ascending
      const titleHeader = screen.getByRole('button', { name: /title/i })
      fireEvent.click(titleHeader)

      await waitFor(() => {
        const taskRows = screen.getAllByRole('row')
        expect(taskRows[1]).toHaveTextContent('Alpha Task')
        expect(taskRows[2]).toHaveTextContent('Beta Task')
        expect(taskRows[3]).toHaveTextContent('Charlie Task')
      })

      // Sort by status
      const statusHeader = screen.getByRole('button', { name: /status/i })
      fireEvent.click(statusHeader)

      await waitFor(() => {
        const taskRows = screen.getAllByRole('row')
        // Should be ordered by status priority: Todo, Backlog, Done
        expect(taskRows[1]).toHaveTextContent('Alpha Task') // Todo
        expect(taskRows[2]).toHaveTextContent('Charlie Task') // Backlog
        expect(taskRows[3]).toHaveTextContent('Beta Task') // Done
      })
    })
  })

  describe('Empty State', () => {
    it('should show empty state message when no tasks', () => {
      mockUseTasks.mockReturnValue({
        ...defaultMockUseTasks,
        tasks: [],
      })

      renderTaskList()

      // Should show empty state
      expect(screen.getByText(/No tasks found/i)).toBeInTheDocument()
      expect(
        screen.getByText(/Create your first task to get started!/i)
      ).toBeInTheDocument()

      // Table headers should not be rendered in empty state
      expect(
        screen.queryByRole('button', { name: /title/i })
      ).not.toBeInTheDocument()
    })
  })

  describe('Mobile Responsive Sorting', () => {
    it('should show sortable headers on mobile', () => {
      renderTaskList()

      // All sortable headers should be visible
      expect(screen.getByRole('button', { name: /title/i })).toBeInTheDocument()
      expect(
        screen.getByRole('button', { name: /status/i })
      ).toBeInTheDocument()
      expect(
        screen.getByRole('button', { name: /created/i })
      ).toBeInTheDocument()

      // Description column should be visible but not sortable (no button)
      expect(screen.getByText('Description')).toBeInTheDocument()
      expect(
        screen.queryByRole('button', { name: /description/i })
      ).not.toBeInTheDocument()
    })
  })

  describe('Tooltip Functionality', () => {
    it('should show cursor help styling on created date with tooltip', () => {
      renderTaskList()

      // Find created date elements (they should have relative dates like "2y ago")
      const dateElements = screen.getAllByText(/ago$|Today|Yesterday/)

      // Verify at least one date element exists with proper cursor styling
      expect(dateElements.length).toBeGreaterThan(0)

      // Check that date elements have cursor help styling
      dateElements.forEach(element => {
        expect(element).toHaveStyle('cursor: help')
      })
    })

    it('should have tooltip structure in place for completed dates', () => {
      renderTaskList()

      // Find the table to ensure it rendered
      const table = screen.getByRole('table')
      expect(table).toBeInTheDocument()

      // Verify that the TaskList component rendered without errors
      // The tooltip functionality would be tested in e2e tests for actual hover behavior
      expect(screen.getByText('Beta Task')).toBeInTheDocument()
    })
  })

  describe('Loading and Error States', () => {
    it('should not render sort headers during loading', () => {
      mockUseTasks.mockReturnValue({
        ...defaultMockUseTasks,
        loading: true,
        tasks: [],
      })

      renderTaskList()

      // Should show loading spinner instead of table
      expect(
        screen.queryByRole('button', { name: /title/i })
      ).not.toBeInTheDocument()
      expect(screen.getByText('Loading...')).toBeInTheDocument()
    })

    it('should not render sort headers during error state', () => {
      mockUseTasks.mockReturnValue({
        ...defaultMockUseTasks,
        error: 'Failed to load tasks',
        tasks: [],
      })

      renderTaskList()

      // Should show error message instead of table
      expect(
        screen.queryByRole('button', { name: /title/i })
      ).not.toBeInTheDocument()
      expect(screen.getByText(/Error loading tasks/i)).toBeInTheDocument()
    })
  })
})
