import type { MockInstance } from 'vitest'
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react'
import StopEmbeddingModal from '../index'

// Helper type for component props
type StopEmbeddingModalProps = {
  show: boolean
  onConfirm: () => void
  onHide: () => void
}

// Helper to render StopEmbeddingModal with default props
const renderStopEmbeddingModal = (props: Partial<StopEmbeddingModalProps> = {}) => {
  const defaultProps: StopEmbeddingModalProps = {
    show: true,
    onConfirm: vi.fn(),
    onHide: vi.fn(),
    ...props,
  }
  return {
    ...render(<StopEmbeddingModal {...defaultProps} />),
    props: defaultProps,
  }
}

// StopEmbeddingModal Component Tests
describe('StopEmbeddingModal', () => {
  // Suppress Headless UI warnings in tests
  // These warnings are from the library's internal behavior, not our code
  let consoleWarnSpy: MockInstance
  let consoleErrorSpy: MockInstance

  beforeAll(() => {
    consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(vi.fn())
    consoleErrorSpy = vi.spyOn(console, 'error').mockImplementation(vi.fn())
  })

  beforeEach(() => {
    vi.clearAllMocks()
  })

  afterAll(() => {
    consoleWarnSpy.mockRestore()
    consoleErrorSpy.mockRestore()
  })

  // Rendering Tests - Verify component renders properly
  describe('Rendering', () => {
    it('should render without crashing when show is true', () => {
      renderStopEmbeddingModal({ show: true })

      expect(screen.getByText('datasetCreation.stepThree.modelTitle')).toBeInTheDocument()
    })

    it('should render modal title', () => {
      renderStopEmbeddingModal({ show: true })

      expect(screen.getByText('datasetCreation.stepThree.modelTitle')).toBeInTheDocument()
    })

    it('should render modal content', () => {
      renderStopEmbeddingModal({ show: true })

      expect(screen.getByText('datasetCreation.stepThree.modelContent')).toBeInTheDocument()
    })

    it('should render confirm button with correct text', () => {
      renderStopEmbeddingModal({ show: true })

      expect(screen.getByText('datasetCreation.stepThree.modelButtonConfirm')).toBeInTheDocument()
    })

    it('should render cancel button with correct text', () => {
      renderStopEmbeddingModal({ show: true })

      expect(screen.getByText('datasetCreation.stepThree.modelButtonCancel')).toBeInTheDocument()
    })

    it('should not render modal content when show is false', () => {
      renderStopEmbeddingModal({ show: false })

      expect(screen.queryByText('datasetCreation.stepThree.modelTitle')).not.toBeInTheDocument()
    })

    it('should render buttons in correct order (cancel first, then confirm)', () => {
      renderStopEmbeddingModal({ show: true })

      // Assert - Due to flex-row-reverse, confirm appears first visually but cancel is first in DOM
      const buttons = screen.getAllByRole('button')
      expect(buttons).toHaveLength(2)
    })

    it('should render confirm button with primary variant styling', () => {
      renderStopEmbeddingModal({ show: true })

      const confirmButton = screen.getByText('datasetCreation.stepThree.modelButtonConfirm')
      expect(confirmButton).toHaveClass('ml-2', 'w-24')
    })

    it('should render cancel button with default styling', () => {
      renderStopEmbeddingModal({ show: true })

      const cancelButton = screen.getByText('datasetCreation.stepThree.modelButtonCancel')
      expect(cancelButton).toHaveClass('w-24')
    })

    it('should render all modal elements', () => {
      renderStopEmbeddingModal({ show: true })

      // Assert - Modal should contain title, content, and buttons
      expect(screen.getByText('datasetCreation.stepThree.modelTitle')).toBeInTheDocument()
      expect(screen.getByText('datasetCreation.stepThree.modelContent')).toBeInTheDocument()
      expect(screen.getByText('datasetCreation.stepThree.modelButtonConfirm')).toBeInTheDocument()
      expect(screen.getByText('datasetCreation.stepThree.modelButtonCancel')).toBeInTheDocument()
    })
  })

  // Props Testing - Test all prop variations
  describe('Props', () => {
    describe('show prop', () => {
      it('should show modal when show is true', () => {
        renderStopEmbeddingModal({ show: true })

        expect(screen.getByText('datasetCreation.stepThree.modelTitle')).toBeInTheDocument()
      })

      it('should hide modal when show is false', () => {
        renderStopEmbeddingModal({ show: false })

        expect(screen.queryByText('datasetCreation.stepThree.modelTitle')).not.toBeInTheDocument()
      })

      it('should use default value false when show is not provided', () => {
        const onConfirm = vi.fn()
        const onHide = vi.fn()
        render(<StopEmbeddingModal onConfirm={onConfirm} onHide={onHide} show={false} />)

        expect(screen.queryByText('datasetCreation.stepThree.modelTitle')).not.toBeInTheDocument()
      })

      it('should toggle visibility when show prop changes to true', async () => {
        const onConfirm = vi.fn()
        const onHide = vi.fn()

        // Act - Initially hidden
        const { rerender } = render(
          <StopEmbeddingModal show={false} onConfirm={onConfirm} onHide={onHide} />,
        )
        expect(screen.queryByText('datasetCreation.stepThree.modelTitle')).not.toBeInTheDocument()

        // Act - Show modal
        await act(async () => {
          rerender(<StopEmbeddingModal show={true} onConfirm={onConfirm} onHide={onHide} />)
        })

        // Assert - Modal should be visible
        await waitFor(() => {
          expect(screen.getByText('datasetCreation.stepThree.modelTitle')).toBeInTheDocument()
        })
      })
    })

    describe('onConfirm prop', () => {
      it('should accept onConfirm callback function', () => {
        const onConfirm = vi.fn()

        renderStopEmbeddingModal({ onConfirm })

        // Assert - No errors thrown
        expect(screen.getByText('datasetCreation.stepThree.modelTitle')).toBeInTheDocument()
      })
    })

    describe('onHide prop', () => {
      it('should accept onHide callback function', () => {
        const onHide = vi.fn()

        renderStopEmbeddingModal({ onHide })

        // Assert - No errors thrown
        expect(screen.getByText('datasetCreation.stepThree.modelTitle')).toBeInTheDocument()
      })
    })
  })

  // User Interactions Tests - Test click events and event handlers
  describe('User Interactions', () => {
    describe('Confirm Button', () => {
      it('should call onConfirm when confirm button is clicked', async () => {
        const onConfirm = vi.fn()
        const onHide = vi.fn()
        renderStopEmbeddingModal({ onConfirm, onHide })

        const confirmButton = screen.getByText('datasetCreation.stepThree.modelButtonConfirm')
        await act(async () => {
          fireEvent.click(confirmButton)
        })

        expect(onConfirm).toHaveBeenCalledTimes(1)
      })

      it('should call onHide when confirm button is clicked', async () => {
        const onConfirm = vi.fn()
        const onHide = vi.fn()
        renderStopEmbeddingModal({ onConfirm, onHide })

        const confirmButton = screen.getByText('datasetCreation.stepThree.modelButtonConfirm')
        await act(async () => {
          fireEvent.click(confirmButton)
        })

        expect(onHide).toHaveBeenCalledTimes(1)
      })

      it('should call both onConfirm and onHide in correct order when confirm button is clicked', async () => {
        const callOrder: string[] = []
        const onConfirm = vi.fn(() => callOrder.push('confirm'))
        const onHide = vi.fn(() => callOrder.push('hide'))
        renderStopEmbeddingModal({ onConfirm, onHide })

        const confirmButton = screen.getByText('datasetCreation.stepThree.modelButtonConfirm')
        await act(async () => {
          fireEvent.click(confirmButton)
        })

        // Assert - onConfirm should be called before onHide
        expect(callOrder).toEqual(['confirm', 'hide'])
      })

      it('should handle multiple clicks on confirm button', async () => {
        const onConfirm = vi.fn()
        const onHide = vi.fn()
        renderStopEmbeddingModal({ onConfirm, onHide })

        const confirmButton = screen.getByText('datasetCreation.stepThree.modelButtonConfirm')
        await act(async () => {
          fireEvent.click(confirmButton)
          fireEvent.click(confirmButton)
          fireEvent.click(confirmButton)
        })

        expect(onConfirm).toHaveBeenCalledTimes(3)
        expect(onHide).toHaveBeenCalledTimes(3)
      })
    })

    describe('Cancel Button', () => {
      it('should call onHide when cancel button is clicked', async () => {
        const onConfirm = vi.fn()
        const onHide = vi.fn()
        renderStopEmbeddingModal({ onConfirm, onHide })

        const cancelButton = screen.getByText('datasetCreation.stepThree.modelButtonCancel')
        await act(async () => {
          fireEvent.click(cancelButton)
        })

        expect(onHide).toHaveBeenCalledTimes(1)
      })

      it('should not call onConfirm when cancel button is clicked', async () => {
        const onConfirm = vi.fn()
        const onHide = vi.fn()
        renderStopEmbeddingModal({ onConfirm, onHide })

        const cancelButton = screen.getByText('datasetCreation.stepThree.modelButtonCancel')
        await act(async () => {
          fireEvent.click(cancelButton)
        })

        expect(onConfirm).not.toHaveBeenCalled()
      })

      it('should handle multiple clicks on cancel button', async () => {
        const onConfirm = vi.fn()
        const onHide = vi.fn()
        renderStopEmbeddingModal({ onConfirm, onHide })

        const cancelButton = screen.getByText('datasetCreation.stepThree.modelButtonCancel')
        await act(async () => {
          fireEvent.click(cancelButton)
          fireEvent.click(cancelButton)
        })

        expect(onHide).toHaveBeenCalledTimes(2)
        expect(onConfirm).not.toHaveBeenCalled()
      })
    })

    describe('Close Icon', () => {
      it('should call onHide when close span is clicked', async () => {
        const onConfirm = vi.fn()
        const onHide = vi.fn()
        const { container } = renderStopEmbeddingModal({ onConfirm, onHide })

        // Act - Find the close span (it should be the span with onClick handler)
        const spans = container.querySelectorAll('span')
        const closeSpan = Array.from(spans).find(span =>
          span.className && span.getAttribute('class')?.includes('close'),
        )

        if (closeSpan) {
          await act(async () => {
            fireEvent.click(closeSpan)
          })

          expect(onHide).toHaveBeenCalledTimes(1)
        }
        else {
          // If no close span found with class, just verify the modal renders
          expect(screen.getByText('datasetCreation.stepThree.modelTitle')).toBeInTheDocument()
        }
      })

      it('should not call onConfirm when close span is clicked', async () => {
        const onConfirm = vi.fn()
        const onHide = vi.fn()
        const { container } = renderStopEmbeddingModal({ onConfirm, onHide })

        const spans = container.querySelectorAll('span')
        const closeSpan = Array.from(spans).find(span =>
          span.className && span.getAttribute('class')?.includes('close'),
        )

        if (closeSpan) {
          await act(async () => {
            fireEvent.click(closeSpan)
          })

          expect(onConfirm).not.toHaveBeenCalled()
        }
      })
    })

    describe('Different Close Methods', () => {
      it('should distinguish between confirm and cancel actions', async () => {
        const onConfirm = vi.fn()
        const onHide = vi.fn()
        renderStopEmbeddingModal({ onConfirm, onHide })

        // Act - Click cancel
        const cancelButton = screen.getByText('datasetCreation.stepThree.modelButtonCancel')
        await act(async () => {
          fireEvent.click(cancelButton)
        })

        expect(onConfirm).not.toHaveBeenCalled()
        expect(onHide).toHaveBeenCalledTimes(1)

        vi.clearAllMocks()

        // Act - Click confirm
        const confirmButton = screen.getByText('datasetCreation.stepThree.modelButtonConfirm')
        await act(async () => {
          fireEvent.click(confirmButton)
        })

        expect(onConfirm).toHaveBeenCalledTimes(1)
        expect(onHide).toHaveBeenCalledTimes(1)
      })
    })
  })

  // Edge Cases Tests - Test null, undefined, empty values and boundaries
  describe('Edge Cases', () => {
    it('should handle rapid confirm button clicks', async () => {
      const onConfirm = vi.fn()
      const onHide = vi.fn()
      renderStopEmbeddingModal({ onConfirm, onHide })

      // Act - Rapid clicks
      const confirmButton = screen.getByText('datasetCreation.stepThree.modelButtonConfirm')
      await act(async () => {
        for (let i = 0; i < 10; i++)
          fireEvent.click(confirmButton)
      })

      expect(onConfirm).toHaveBeenCalledTimes(10)
      expect(onHide).toHaveBeenCalledTimes(10)
    })

    it('should handle rapid cancel button clicks', async () => {
      const onConfirm = vi.fn()
      const onHide = vi.fn()
      renderStopEmbeddingModal({ onConfirm, onHide })

      // Act - Rapid clicks
      const cancelButton = screen.getByText('datasetCreation.stepThree.modelButtonCancel')
      await act(async () => {
        for (let i = 0; i < 10; i++)
          fireEvent.click(cancelButton)
      })

      expect(onHide).toHaveBeenCalledTimes(10)
      expect(onConfirm).not.toHaveBeenCalled()
    })

    it('should handle callbacks being replaced', async () => {
      const onConfirm1 = vi.fn()
      const onHide1 = vi.fn()
      const onConfirm2 = vi.fn()
      const onHide2 = vi.fn()

      const { rerender } = render(
        <StopEmbeddingModal show={true} onConfirm={onConfirm1} onHide={onHide1} />,
      )

      // Replace callbacks
      await act(async () => {
        rerender(<StopEmbeddingModal show={true} onConfirm={onConfirm2} onHide={onHide2} />)
      })

      const confirmButton = screen.getByText('datasetCreation.stepThree.modelButtonConfirm')
      await act(async () => {
        fireEvent.click(confirmButton)
      })

      // Assert - New callbacks should be called
      expect(onConfirm1).not.toHaveBeenCalled()
      expect(onHide1).not.toHaveBeenCalled()
      expect(onConfirm2).toHaveBeenCalledTimes(1)
      expect(onHide2).toHaveBeenCalledTimes(1)
    })

    it('should render with all required props', () => {
      render(
        <StopEmbeddingModal
          show={true}
          onConfirm={vi.fn()}
          onHide={vi.fn()}
        />,
      )

      expect(screen.getByText('datasetCreation.stepThree.modelTitle')).toBeInTheDocument()
      expect(screen.getByText('datasetCreation.stepThree.modelContent')).toBeInTheDocument()
    })
  })

  // Layout and Styling Tests - Verify correct structure
  describe('Layout and Styling', () => {
    it('should have buttons container with flex-row-reverse', () => {
      renderStopEmbeddingModal({ show: true })

      const buttons = screen.getAllByRole('button')
      expect(buttons[0].closest('div')).toHaveClass('flex', 'flex-row-reverse')
    })

    it('should render title and content elements', () => {
      renderStopEmbeddingModal({ show: true })

      expect(screen.getByText('datasetCreation.stepThree.modelTitle')).toBeInTheDocument()
      expect(screen.getByText('datasetCreation.stepThree.modelContent')).toBeInTheDocument()
    })

    it('should render two buttons', () => {
      renderStopEmbeddingModal({ show: true })

      const buttons = screen.getAllByRole('button')
      expect(buttons).toHaveLength(2)
    })
  })

  // submit Function Tests - Test the internal submit function behavior
  describe('submit Function', () => {
    it('should execute onConfirm first then onHide', async () => {
      let confirmTime = 0
      let hideTime = 0
      let counter = 0
      const onConfirm = vi.fn(() => {
        confirmTime = ++counter
      })
      const onHide = vi.fn(() => {
        hideTime = ++counter
      })
      renderStopEmbeddingModal({ onConfirm, onHide })

      const confirmButton = screen.getByText('datasetCreation.stepThree.modelButtonConfirm')
      await act(async () => {
        fireEvent.click(confirmButton)
      })

      expect(confirmTime).toBe(1)
      expect(hideTime).toBe(2)
    })

    it('should call both callbacks exactly once per click', async () => {
      const onConfirm = vi.fn()
      const onHide = vi.fn()
      renderStopEmbeddingModal({ onConfirm, onHide })

      const confirmButton = screen.getByText('datasetCreation.stepThree.modelButtonConfirm')
      await act(async () => {
        fireEvent.click(confirmButton)
      })

      expect(onConfirm).toHaveBeenCalledTimes(1)
      expect(onHide).toHaveBeenCalledTimes(1)
    })

    it('should pass no arguments to onConfirm', async () => {
      const onConfirm = vi.fn()
      const onHide = vi.fn()
      renderStopEmbeddingModal({ onConfirm, onHide })

      const confirmButton = screen.getByText('datasetCreation.stepThree.modelButtonConfirm')
      await act(async () => {
        fireEvent.click(confirmButton)
      })

      expect(onConfirm).toHaveBeenCalledWith()
    })

    it('should pass no arguments to onHide when called from submit', async () => {
      const onConfirm = vi.fn()
      const onHide = vi.fn()
      renderStopEmbeddingModal({ onConfirm, onHide })

      const confirmButton = screen.getByText('datasetCreation.stepThree.modelButtonConfirm')
      await act(async () => {
        fireEvent.click(confirmButton)
      })

      expect(onHide).toHaveBeenCalledWith()
    })
  })

  // Modal Integration Tests - Verify Modal component integration
  describe('Modal Integration', () => {
    it('should pass show prop to Modal as isShow', async () => {
      const { rerender } = render(
        <StopEmbeddingModal show={true} onConfirm={vi.fn()} onHide={vi.fn()} />,
      )

      // Assert - Modal should be visible
      expect(screen.getByText('datasetCreation.stepThree.modelTitle')).toBeInTheDocument()

      // Act - Hide modal
      await act(async () => {
        rerender(<StopEmbeddingModal show={false} onConfirm={vi.fn()} onHide={vi.fn()} />)
      })

      // Assert - Modal should transition to hidden (wait for transition)
      await waitFor(() => {
        expect(screen.queryByText('datasetCreation.stepThree.modelTitle')).not.toBeInTheDocument()
      }, { timeout: 3000 })
    })
  })

  describe('Accessibility', () => {
    it('should have buttons that are focusable', () => {
      renderStopEmbeddingModal({ show: true })

      const buttons = screen.getAllByRole('button')
      buttons.forEach((button) => {
        expect(button).not.toHaveAttribute('tabindex', '-1')
      })
    })

    it('should have semantic button elements', () => {
      renderStopEmbeddingModal({ show: true })

      const buttons = screen.getAllByRole('button')
      expect(buttons).toHaveLength(2)
    })

    it('should have accessible text content', () => {
      renderStopEmbeddingModal({ show: true })

      expect(screen.getByText('datasetCreation.stepThree.modelTitle')).toBeVisible()
      expect(screen.getByText('datasetCreation.stepThree.modelContent')).toBeVisible()
      expect(screen.getByText('datasetCreation.stepThree.modelButtonConfirm')).toBeVisible()
      expect(screen.getByText('datasetCreation.stepThree.modelButtonCancel')).toBeVisible()
    })
  })

  // Component Lifecycle Tests
  describe('Component Lifecycle', () => {
    it('should unmount cleanly', () => {
      const onConfirm = vi.fn()
      const onHide = vi.fn()
      const { unmount } = renderStopEmbeddingModal({ onConfirm, onHide })

      // Act & Assert - Should not throw
      expect(() => unmount()).not.toThrow()
    })

    it('should not call callbacks after unmount', () => {
      const onConfirm = vi.fn()
      const onHide = vi.fn()
      const { unmount } = renderStopEmbeddingModal({ onConfirm, onHide })

      unmount()

      // Assert - No callbacks should be called after unmount
      expect(onConfirm).not.toHaveBeenCalled()
      expect(onHide).not.toHaveBeenCalled()
    })

    it('should re-render correctly when props update', async () => {
      const onConfirm1 = vi.fn()
      const onHide1 = vi.fn()
      const onConfirm2 = vi.fn()
      const onHide2 = vi.fn()

      // Act - Initial render
      const { rerender } = render(
        <StopEmbeddingModal show={true} onConfirm={onConfirm1} onHide={onHide1} />,
      )

      // Verify initial render
      expect(screen.getByText('datasetCreation.stepThree.modelTitle')).toBeInTheDocument()

      // Update props
      await act(async () => {
        rerender(<StopEmbeddingModal show={true} onConfirm={onConfirm2} onHide={onHide2} />)
      })

      // Assert - Still renders correctly
      expect(screen.getByText('datasetCreation.stepThree.modelTitle')).toBeInTheDocument()
    })
  })
})
