import { render, screen, fireEvent, waitFor } from '@testing-library/react'
import { UnifiedTable } from '../../index'
import { ColumnConfig, BulkAction } from '../../types'
import { Mail, Trash } from 'lucide-react'
import { useState } from 'react'

interface TestData {
  id: string
  name: string
  email: string
  status: string
}

describe('UnifiedTable - Integration Tests with Selection', () => {
  const mockData: TestData[] = Array.from({ length: 50 }, (_, i) => ({
    id: `${i + 1}`,
    name: `User ${i + 1}`,
    email: `user${i + 1}@example.com`,
    status: i % 2 === 0 ? 'active' : 'inactive',
  }))

  const columns: ColumnConfig<TestData>[] = [
    {
      id: 'name',
      header: 'Name',
      accessorKey: 'name',
      sortable: true,
    },
    {
      id: 'email',
      header: 'Email',
      accessorKey: 'email',
      sortable: true,
    },
    {
      id: 'status',
      header: 'Status',
      accessorKey: 'status',
      sortable: true,
    },
  ]

  const getRowId = (row: TestData) => row.id

  describe('Basic Selection Functionality', () => {
    it('should render table with selection enabled', () => {
      render(
        <UnifiedTable
          data={mockData.slice(0, 10)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
        />
      )

      // Should have checkboxes
      const checkboxes = screen.getAllByRole('checkbox')
      expect(checkboxes.length).toBeGreaterThan(0)
    })

    it('should select individual rows', () => {
      render(
        <UnifiedTable
          data={mockData.slice(0, 10)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      // First checkbox is "select all", second is first row
      fireEvent.click(checkboxes[1])

      expect(screen.getByText(/1 item selected/)).toBeInTheDocument()
    })

    it('should select multiple rows individually', () => {
      render(
        <UnifiedTable
          data={mockData.slice(0, 10)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      fireEvent.click(checkboxes[1])
      fireEvent.click(checkboxes[2])
      fireEvent.click(checkboxes[3])

      expect(screen.getByText(/3 items selected/)).toBeInTheDocument()
    })

    it('should deselect rows', () => {
      render(
        <UnifiedTable
          data={mockData.slice(0, 10)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      fireEvent.click(checkboxes[1])
      expect(screen.getByText(/1 item selected/)).toBeInTheDocument()

      fireEvent.click(checkboxes[1])
      expect(screen.queryByText(/item selected/)).not.toBeInTheDocument()
    })
  })

  describe('Select All on Current Page', () => {
    it('should select all rows on current page', () => {
      render(
        <UnifiedTable
          data={mockData.slice(0, 10)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      // First checkbox is "select all"
      fireEvent.click(checkboxes[0])

      expect(screen.getByText(/10 items selected on this page/)).toBeInTheDocument()
    })

    it('should deselect all rows when clicking select all again', () => {
      render(
        <UnifiedTable
          data={mockData.slice(0, 10)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      fireEvent.click(checkboxes[0])
      expect(screen.getByText(/10 items selected/)).toBeInTheDocument()

      fireEvent.click(checkboxes[0])
      expect(screen.queryByText(/items selected/)).not.toBeInTheDocument()
    })
  })

  describe('Select All Pages', () => {
    it('should show select all pages option when pagination enabled', () => {
      render(
        <UnifiedTable
          data={mockData.slice(0, 25)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
          pagination={{
            enabled: true,
            pageSize: 10,
            totalCount: 50,
            currentPage: 1,
            serverSide: false,
            onPageChange: jest.fn(),
          }}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      fireEvent.click(checkboxes[0])

      // Check that the select all button is present (there's a span and button, target the button)
      expect(screen.getByRole('button', { name: /Select all 50 items/ })).toBeInTheDocument()
    })

    it('should select all pages when button clicked', async () => {
      render(
        <UnifiedTable
          data={mockData.slice(0, 25)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
          pagination={{
            enabled: true,
            pageSize: 10,
            totalCount: 50,
            currentPage: 1,
            serverSide: false,
            onPageChange: jest.fn(),
          }}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      fireEvent.click(checkboxes[0])

      const selectAllButton = screen.getByRole('button', { name: /Select all 50 items/ })
      fireEvent.click(selectAllButton)

      await waitFor(() => {
        // After selecting all pages, the bulk action bar should show the total count
        expect(screen.getByText((content, element) => {
          const tagName = element?.tagName.toLowerCase() || ''
          const className = element?.className || ''
          const textContent = element?.textContent || ''
          return tagName === 'span' &&
                 typeof className === 'string' && className.includes('text-blue-600') &&
                 textContent.includes('All') &&
                 textContent.includes('50') &&
                 textContent.includes('items selected')
        })).toBeInTheDocument()
      })
    })
  })

  describe('Bulk Actions with Selection', () => {
    it('should show bulk action bar when items selected', () => {
      const bulkActions: BulkAction[] = [
        {
          id: 'email',
          label: 'Send Email',
          icon: Mail,
          variant: 'gradient-purple',
          onClick: jest.fn(),
        },
      ]

      render(
        <UnifiedTable
          data={mockData.slice(0, 10)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
          bulkActions={bulkActions}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      fireEvent.click(checkboxes[1])

      expect(screen.getByText('Send Email')).toBeInTheDocument()
    })

    it('should execute bulk action on selected items', async () => {
      const onBulkAction = jest.fn()
      const bulkActions: BulkAction[] = [
        {
          id: 'email',
          label: 'Send Email',
          icon: Mail,
          variant: 'gradient-purple',
          onClick: onBulkAction,
        },
      ]

      render(
        <UnifiedTable
          data={mockData.slice(0, 10)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
          bulkActions={bulkActions}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      fireEvent.click(checkboxes[1])
      fireEvent.click(checkboxes[2])

      const emailButton = screen.getByText('Send Email')
      fireEvent.click(emailButton)

      await waitFor(() => {
        expect(onBulkAction).toHaveBeenCalledWith(expect.any(Set))
        const selectedIds = onBulkAction.mock.calls[0][0]
        expect(selectedIds.size).toBe(2)
      })
    })

    it('should clear selection after bulk action', async () => {
      const onBulkAction = jest.fn().mockResolvedValue(undefined)
      const bulkActions: BulkAction[] = [
        {
          id: 'email',
          label: 'Send Email',
          icon: Mail,
          variant: 'gradient-purple',
          onClick: onBulkAction,
        },
      ]

      render(
        <UnifiedTable
          data={mockData.slice(0, 10)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
          bulkActions={bulkActions}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      fireEvent.click(checkboxes[1])

      const emailButton = screen.getByText('Send Email')
      fireEvent.click(emailButton)

      await waitFor(() => {
        expect(screen.queryByText(/items selected/)).not.toBeInTheDocument()
      })
    })

    it('should show confirmation dialog for actions with confirmMessage', () => {
      const confirmSpy = jest.spyOn(window, 'confirm').mockReturnValue(true)
      const onBulkAction = jest.fn()
      const bulkActions: BulkAction[] = [
        {
          id: 'delete',
          label: 'Delete',
          icon: Trash,
          variant: 'gradient-orange',
          onClick: onBulkAction,
          confirmMessage: 'Are you sure you want to delete {count} items?',
        },
      ]

      render(
        <UnifiedTable
          data={mockData.slice(0, 10)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
          bulkActions={bulkActions}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      fireEvent.click(checkboxes[1])
      fireEvent.click(checkboxes[2])

      const deleteButton = screen.getByText('Delete')
      fireEvent.click(deleteButton)

      expect(confirmSpy).toHaveBeenCalledWith('Are you sure you want to delete 2 items?')
      confirmSpy.mockRestore()
    })

    it('should not execute action when confirmation cancelled', () => {
      const confirmSpy = jest.spyOn(window, 'confirm').mockReturnValue(false)
      const onBulkAction = jest.fn()
      const bulkActions: BulkAction[] = [
        {
          id: 'delete',
          label: 'Delete',
          icon: Trash,
          variant: 'gradient-orange',
          onClick: onBulkAction,
          confirmMessage: 'Are you sure?',
        },
      ]

      render(
        <UnifiedTable
          data={mockData.slice(0, 10)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
          bulkActions={bulkActions}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      fireEvent.click(checkboxes[1])

      const deleteButton = screen.getByText('Delete')
      fireEvent.click(deleteButton)

      expect(onBulkAction).not.toHaveBeenCalled()
      confirmSpy.mockRestore()
    })

    it('should enforce maxSelection limit', () => {
      const onBulkAction = jest.fn()
      const bulkActions: BulkAction[] = [
        {
          id: 'limited',
          label: 'Limited Action',
          icon: Mail,
          variant: 'default',
          onClick: onBulkAction,
          maxSelection: 2,
        },
      ]

      render(
        <UnifiedTable
          data={mockData.slice(0, 10)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
          bulkActions={bulkActions}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      fireEvent.click(checkboxes[1])
      fireEvent.click(checkboxes[2])
      fireEvent.click(checkboxes[3])

      const actionButton = screen.getByText('Limited Action').closest('button')
      expect(actionButton).toBeDisabled()
      expect(actionButton).toHaveAttribute('title', 'Maximum 2 items can be selected for this action')
      expect(onBulkAction).not.toHaveBeenCalled()
    })
  })

  describe('Clear Selection', () => {
    it('should clear selection when clear button clicked', () => {
      const bulkActions: BulkAction[] = [
        {
          id: 'email',
          label: 'Send Email',
          icon: Mail,
          variant: 'default',
          onClick: jest.fn(),
        },
      ]

      const { container } = render(
        <UnifiedTable
          data={mockData.slice(0, 10)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
          bulkActions={bulkActions}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      fireEvent.click(checkboxes[1])
      fireEvent.click(checkboxes[2])

      expect(screen.getByText(/2 items selected/)).toBeInTheDocument()

      const clearButton = screen.getByText('Clear')
      fireEvent.click(clearButton)

      // After clearing, the bulk action bar is hidden with CSS (not removed from DOM)
      // Check that it's hidden via aria-hidden attribute
      const bulkActionBar = container.querySelector('[aria-hidden="true"]')
      expect(bulkActionBar).toBeInTheDocument()
    })
  })

  describe('Selection with Pagination', () => {
    it('should maintain selection when changing pages', async () => {
      const TestComponent = () => {
        const [currentPage, setCurrentPage] = useState(1)
        const pageSize = 10
        const startIndex = (currentPage - 1) * pageSize
        const currentData = mockData.slice(startIndex, startIndex + pageSize)

        return (
          <UnifiedTable
            data={currentData}
            columns={columns}
            tableId="test-table"
            getRowId={getRowId}
            selection={{ enabled: true }}
            pagination={{
              enabled: true,
              pageSize: pageSize,
              totalCount: mockData.length,
              currentPage: currentPage,
              serverSide: false,
              onPageChange: setCurrentPage,
            }}
          />
        )
      }

      render(<TestComponent />)

      // Select items on first page
      const checkboxes = screen.getAllByRole('checkbox')
      fireEvent.click(checkboxes[1])
      expect(screen.getByText(/1 item selected/)).toBeInTheDocument()

      // Go to next page
      const nextButton = screen.getByTitle('Next page')
      fireEvent.click(nextButton)

      await waitFor(() => {
        expect(screen.getByText(/Page 2/)).toBeInTheDocument()
      })

      // Selection should still show
      expect(screen.getByText(/1 item selected/)).toBeInTheDocument()
    })
  })

  describe('External Selection Control', () => {
    it('should call onSelectionChange callback', () => {
      const onSelectionChange = jest.fn()

      render(
        <UnifiedTable
          data={mockData.slice(0, 10)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{
            enabled: true,
            onSelectionChange,
          }}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      fireEvent.click(checkboxes[1])

      expect(onSelectionChange).toHaveBeenCalled()
      const selectedIds = onSelectionChange.mock.calls[0][0]
      expect(selectedIds.size).toBe(1)
    })

    it('should call onSelectAllPages callback', async () => {
      const onSelectAllPages = jest.fn()

      render(
        <UnifiedTable
          data={mockData.slice(0, 25)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{
            enabled: true,
            onSelectAllPages,
          }}
          pagination={{
            enabled: true,
            pageSize: 10,
            totalCount: 50,
            currentPage: 1,
            serverSide: false,
            onPageChange: jest.fn(),
          }}
        />
      )

      const checkboxes = screen.getAllByRole('checkbox')
      fireEvent.click(checkboxes[0])

      const selectAllButton = screen.getByRole('button', { name: /Select all 50 items/ })
      fireEvent.click(selectAllButton)

      await waitFor(() => {
        expect(onSelectAllPages).toHaveBeenCalledWith(true)
      })
    })
  })

  describe('Edge Cases', () => {
    it('should handle empty data with selection enabled', () => {
      render(
        <UnifiedTable
          data={[]}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
        />
      )

      expect(screen.getByText('No results found.')).toBeInTheDocument()
    })

    it('should not show bulk actions bar when no items selected', () => {
      const bulkActions: BulkAction[] = [
        {
          id: 'email',
          label: 'Send Email',
          icon: Mail,
          variant: 'default',
          onClick: jest.fn(),
        },
      ]

      const { container } = render(
        <UnifiedTable
          data={mockData.slice(0, 10)}
          columns={columns}
          tableId="test-table"
          getRowId={getRowId}
          selection={{ enabled: true }}
          bulkActions={bulkActions}
        />
      )

      // Bulk action bar is hidden via CSS, not removed from DOM
      // Check that it has aria-hidden="true" and pointer-events-none
      const bulkActionBar = container.querySelector('[aria-hidden="true"]')
      expect(bulkActionBar).toBeInTheDocument()
      expect(bulkActionBar).toHaveClass('pointer-events-none')
    })
  })
})
