import type { ReactElement } from 'react'
import { fireEvent, screen, waitFor } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { renderWithSystemFeatures } from '@/__tests__/utils/mock-system-features'
import List from '../index'

let mockBrandingEnabled = false
const render = (ui: ReactElement) => renderWithSystemFeatures(ui, {
  systemFeatures: { branding: { enabled: mockBrandingEnabled } },
})

const mockPush = vi.fn()
const mockReplace = vi.fn()
vi.mock('@/next/navigation', () => ({
  useRouter: () => ({
    push: mockPush,
    replace: mockReplace,
  }),
}))

// Mock app context
vi.mock('@/context/app-context', () => ({
  useAppContext: () => ({
    currentWorkspace: { role: 'admin' },
    isCurrentWorkspaceOwner: true,
  }),
  useSelector: () => true,
}))

// Mock external api panel context
const mockSetShowExternalApiPanel = vi.fn()
vi.mock('@/context/external-api-panel-context', () => ({
  useExternalApiPanel: () => ({
    showExternalApiPanel: false,
    setShowExternalApiPanel: mockSetShowExternalApiPanel,
  }),
}))

// Mock useDocumentTitle hook
vi.mock('@/hooks/use-document-title', () => ({
  default: vi.fn(),
}))

// Mock useFormatTimeFromNow hook
vi.mock('@/hooks/use-format-time-from-now', () => ({
  useFormatTimeFromNow: () => ({
    formatTimeFromNow: (timestamp: number) => new Date(timestamp).toLocaleDateString(),
  }),
}))

// Mock useKnowledge hook
vi.mock('@/hooks/use-knowledge', () => ({
  useKnowledge: () => ({
    formatIndexingTechniqueAndMethod: () => 'High Quality',
  }),
}))

vi.mock('@/service/knowledge/use-dataset', () => ({
  useDatasetList: vi.fn(() => ({
    data: { pages: [{ data: [] }] },
    fetchNextPage: vi.fn(),
    hasNextPage: false,
    isFetching: false,
    isFetchingNextPage: false,
  })),
  useInvalidDatasetList: () => vi.fn(),
  useDatasetApiBaseUrl: () => ({
    data: { api_base_url: 'https://api.example.com' },
  }),
}))

// Mock Datasets component
vi.mock('../datasets', () => ({
  default: ({ tags, keywords, includeAll }: { tags: string[], keywords: string, includeAll: boolean }) => (
    <div data-testid="datasets-component">
      <span data-testid="tags">{tags.join(',')}</span>
      <span data-testid="keywords">{keywords}</span>
      <span data-testid="include-all">{includeAll ? 'true' : 'false'}</span>
    </div>
  ),
}))

// Mock DatasetFooter component
vi.mock('../dataset-footer', () => ({
  default: () => <footer data-testid="dataset-footer">Footer</footer>,
}))

// Mock ExternalAPIPanel component
vi.mock('../../external-api/external-api-panel', () => ({
  default: ({ onClose }: { onClose: () => void }) => (
    <div data-testid="external-api-panel">
      <button onClick={onClose}>Close Panel</button>
    </div>
  ),
}))

// Mock SecretKeyModal — it depends on user profile context and service APIs
// not configured in this test. ServiceApi always mounts the modal (controlled
// by `isShow`) so we provide a lightweight stub.
vi.mock('@/app/components/develop/secret-key/secret-key-modal', () => ({
  default: ({ isShow }: { isShow: boolean }) =>
    isShow ? <div data-testid="secret-key-modal" /> : null,
}))

// Mock TagManagementModal
vi.mock('@/features/tag-management/components/tag-management-modal', () => ({
  TagManagementModal: ({ show }: { show: boolean }) => show ? <div data-testid="tag-management-modal" /> : null,
}))

// Mock TagFilter
vi.mock('@/features/tag-management/components/tag-filter', () => ({
  TagFilter: ({ onChange, onOpenTagManagement }: { value: string[], onChange: (val: string[]) => void, onOpenTagManagement: () => void }) => (
    <div data-testid="tag-filter">
      <button onClick={() => onChange(['tag-1', 'tag-2'])}>Select Tags</button>
      <button onClick={onOpenTagManagement}>Manage Tags</button>
    </div>
  ),
}))

// Mock CheckboxWithLabel
vi.mock('@/app/components/datasets/create/website/base/checkbox-with-label', () => ({
  default: ({ isChecked, onChange, label }: { isChecked: boolean, onChange: () => void, label: string }) => (
    <label>
      <input
        type="checkbox"
        checked={isChecked}
        onChange={onChange}
        data-testid="include-all-checkbox"
      />
      {label}
    </label>
  ),
}))

describe('List', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    mockBrandingEnabled = false
  })

  describe('Rendering', () => {
    it('should render without crashing', () => {
      render(<List />)
      expect(screen.getByTestId('datasets-component')).toBeInTheDocument()
    })

    it('should render the search input', () => {
      render(<List />)
      expect(screen.getByRole('textbox')).toBeInTheDocument()
    })

    it('should render tag filter', () => {
      render(<List />)
      expect(screen.getByTestId('tag-filter')).toBeInTheDocument()
    })

    it('should render external API panel button', () => {
      render(<List />)
      expect(screen.getByText(/externalAPIPanelTitle/)).toBeInTheDocument()
    })

    it('should render dataset footer when branding is disabled', () => {
      render(<List />)
      expect(screen.getByTestId('dataset-footer')).toBeInTheDocument()
    })
  })

  describe('Props', () => {
    it('should pass includeAll prop to Datasets', () => {
      render(<List />)
      expect(screen.getByTestId('include-all')).toHaveTextContent('false')
    })

    it('should pass empty keywords initially', () => {
      render(<List />)
      expect(screen.getByTestId('keywords')).toHaveTextContent('')
    })

    it('should pass empty tags initially', () => {
      render(<List />)
      expect(screen.getByTestId('tags')).toHaveTextContent('')
    })
  })

  describe('User Interactions', () => {
    it('should open external API panel when button is clicked', () => {
      render(<List />)

      const button = screen.getByText(/externalAPIPanelTitle/)
      fireEvent.click(button)

      expect(mockSetShowExternalApiPanel).toHaveBeenCalledWith(true)
    })

    it('should update search input value', () => {
      render(<List />)

      const input = screen.getByRole('textbox')
      fireEvent.change(input, { target: { value: 'test search' } })

      expect(input).toHaveValue('test search')
    })

    it('should trigger tag filter change', () => {
      render(<List />)
      // Tag filter is rendered and interactive
      const selectTagsBtn = screen.getByText('Select Tags')
      expect(selectTagsBtn).toBeInTheDocument()
      fireEvent.click(selectTagsBtn)
      // The onChange callback was triggered (debounced)
    })
  })

  describe('Conditional Rendering', () => {
    it('should show include all checkbox for workspace owner', () => {
      render(<List />)
      expect(screen.getByTestId('include-all-checkbox')).toBeInTheDocument()
    })
  })

  describe('Styles', () => {
    it('should have correct container styling', () => {
      const { container } = render(<List />)
      const mainContainer = container.firstChild as HTMLElement
      expect(mainContainer).toHaveClass('relative', 'flex', 'grow', 'flex-col')
    })
  })

  describe('Edge Cases', () => {
    it('should handle empty state gracefully', () => {
      render(<List />)
      // Should render without errors even with empty data
      expect(screen.getByTestId('datasets-component')).toBeInTheDocument()
    })
  })

  describe('Branch Coverage', () => {
    it('should not redirect normal role users at component level', async () => {
      // Re-mock useAppContext with normal role
      vi.doMock('@/context/app-context', () => ({
        useAppContext: () => ({
          currentWorkspace: { role: 'normal' },
          isCurrentWorkspaceOwner: false,
        }),
        useSelector: () => true,
      }))

      // Clear module cache and re-import
      vi.resetModules()
      const { default: ListComponent } = await import('../index')

      render(<ListComponent />)

      await waitFor(() => {
        expect(mockReplace).not.toHaveBeenCalled()
      })
    })

    it('should clear search input when onClear is called', () => {
      render(<List />)

      const input = screen.getByRole('textbox')
      // First set a value
      fireEvent.change(input, { target: { value: 'test search' } })
      expect(input).toHaveValue('test search')

      // Find and click the clear button
      const clearButton = document.querySelector('[class*="clear"], button[aria-label*="clear"]')
      if (clearButton) {
        fireEvent.click(clearButton)
        expect(input).toHaveValue('')
      }
    })

    it('should show ExternalAPIPanel when showExternalApiPanel is true', async () => {
      // Re-mock to show external API panel
      vi.doMock('@/context/external-api-panel-context', () => ({
        useExternalApiPanel: () => ({
          showExternalApiPanel: true,
          setShowExternalApiPanel: mockSetShowExternalApiPanel,
        }),
      }))

      vi.resetModules()
      const { default: ListComponent } = await import('../index')

      render(<ListComponent />)

      expect(screen.getByTestId('external-api-panel')).toBeInTheDocument()
    })

    it('should close ExternalAPIPanel when onClose is called', async () => {
      vi.doMock('@/context/external-api-panel-context', () => ({
        useExternalApiPanel: () => ({
          showExternalApiPanel: true,
          setShowExternalApiPanel: mockSetShowExternalApiPanel,
        }),
      }))

      vi.resetModules()
      const { default: ListComponent } = await import('../index')

      render(<ListComponent />)

      const closeButton = screen.getByText('Close Panel')
      fireEvent.click(closeButton)

      expect(mockSetShowExternalApiPanel).toHaveBeenCalledWith(false)
    })

    it('should show TagManagementModal when tag management is opened', () => {
      render(<List />)
      fireEvent.click(screen.getByText('Manage Tags'))

      expect(screen.getByTestId('tag-management-modal')).toBeInTheDocument()
    })

    it('should not show DatasetFooter when branding is enabled', async () => {
      mockBrandingEnabled = true

      render(<List />)

      expect(screen.queryByTestId('dataset-footer')).not.toBeInTheDocument()
    })

    it('should not show include all checkbox when not workspace owner', async () => {
      vi.doMock('@/context/app-context', () => ({
        useAppContext: () => ({
          currentWorkspace: { role: 'editor' },
          isCurrentWorkspaceOwner: false,
        }),
        useSelector: () => true,
      }))

      vi.resetModules()
      const { default: ListComponent } = await import('../index')

      render(<ListComponent />)

      expect(screen.queryByTestId('include-all-checkbox')).not.toBeInTheDocument()
    })
  })
})
