import type { PluginDeclaration, UpdateFromGitHubPayload } from '../../../../types'
import { fireEvent, render, screen, waitFor, within } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { PluginCategoryEnum } from '../../../../types'
import SelectPackage from '../selectPackage'

type SelectOption = {
  value: string | number
  name: string
}

// Mock upload helper from hooks module
const { mockHandleUpload } = vi.hoisted(() => ({
  mockHandleUpload: vi.fn(),
}))
vi.mock('../../../hooks', async (importOriginal) => {
  const actual = await importOriginal<typeof import('../../../hooks')>()
  return {
    ...actual,
    handleUpload: mockHandleUpload,
  }
})

vi.mock('@langgenius/dify-ui/select', async () => {
  const React = await import('react')
  const SelectContext = React.createContext<{
    readOnly?: boolean
    onValueChange?: (value: string) => void
  }>({})

  return {
    Select: ({ children, readOnly, onValueChange }: {
      children: React.ReactNode
      readOnly?: boolean
      onValueChange?: (value: string) => void
    }) => (
      <SelectContext.Provider value={{ readOnly, onValueChange }}>
        <div>{children}</div>
      </SelectContext.Provider>
    ),
    SelectLabel: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
    SelectTrigger: ({ children }: { children: React.ReactNode }) => {
      const context = React.useContext(SelectContext)
      return (
        <div>
          <div data-testid="select-trigger" className={context.readOnly ? 'cursor-not-allowed' : 'cursor-pointer'}>
            {children}
          </div>
          <button data-testid="select-empty" type="button" onClick={() => context.onValueChange?.('')}>
            empty select value
          </button>
          <button data-testid="select-invalid" type="button" onClick={() => context.onValueChange?.('__missing__')}>
            invalid select value
          </button>
        </div>
      )
    },
    SelectContent: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
    SelectItem: ({ children, value }: { children: React.ReactNode, value: string }) => {
      const context = React.useContext(SelectContext)
      return (
        <button type="button" onClick={() => context.onValueChange?.(value)}>
          {children}
        </button>
      )
    },
    SelectItemText: ({ children }: { children: React.ReactNode }) => <>{children}</>,
    SelectItemIndicator: () => null,
  }
})

// Factory functions
const createMockManifest = (): PluginDeclaration => ({
  plugin_unique_identifier: 'test-uid',
  version: '1.0.0',
  author: 'test-author',
  icon: 'icon.png',
  name: 'Test Plugin',
  category: PluginCategoryEnum.tool,
  label: { 'en-US': 'Test' } as PluginDeclaration['label'],
  description: { 'en-US': 'Test Description' } as PluginDeclaration['description'],
  created_at: '2024-01-01',
  resource: {},
  plugins: [],
  verified: true,
  endpoint: { settings: [], endpoints: [] },
  model: null,
  tags: [],
  agent_strategy: null,
  meta: { version: '1.0.0' },
  trigger: {} as PluginDeclaration['trigger'],
})

const createVersions = (): SelectOption[] => [
  { value: 'v1.0.0', name: 'v1.0.0' },
  { value: 'v0.9.0', name: 'v0.9.0' },
]

const createPackages = (): SelectOption[] => [
  { value: 'plugin.zip', name: 'plugin.zip' },
  { value: 'plugin.tar.gz', name: 'plugin.tar.gz' },
]

const createUpdatePayload = (): UpdateFromGitHubPayload => ({
  originalPackageInfo: {
    id: 'original-id',
    repo: 'owner/repo',
    version: 'v0.9.0',
    package: 'plugin.zip',
    releases: [],
  },
})

// Test props type - updatePayload is optional for testing
type TestProps = {
  updatePayload?: UpdateFromGitHubPayload
  repoUrl?: string
  selectedVersion?: string
  versions?: SelectOption[]
  onSelectVersion?: (item: SelectOption) => void
  selectedPackage?: string
  packages?: SelectOption[]
  onSelectPackage?: (item: SelectOption) => void
  onUploaded?: (result: { uniqueIdentifier: string, manifest: PluginDeclaration }) => void
  onFailed?: (errorMsg: string) => void
  onBack?: () => void
}

describe('SelectPackage', () => {
  const createDefaultProps = () => ({
    updatePayload: undefined as UpdateFromGitHubPayload | undefined,
    repoUrl: 'https://github.com/owner/repo',
    selectedVersion: '',
    versions: createVersions(),
    onSelectVersion: vi.fn() as (item: SelectOption) => void,
    selectedPackage: '',
    packages: createPackages(),
    onSelectPackage: vi.fn() as (item: SelectOption) => void,
    onUploaded: vi.fn() as (result: { uniqueIdentifier: string, manifest: PluginDeclaration }) => void,
    onFailed: vi.fn() as (errorMsg: string) => void,
    onBack: vi.fn() as () => void,
  })

  // Helper function to render with proper type handling
  const renderSelectPackage = (overrides: TestProps = {}) => {
    const props = { ...createDefaultProps(), ...overrides }
    // Cast to any to bypass strict type checking since component accepts optional updatePayload
    return render(<SelectPackage {...(props as Parameters<typeof SelectPackage>[0])} />)
  }

  const getSection = (label: string): HTMLElement => {
    const labelElement = screen.getByText(label)
    const labelContainer = labelElement.closest('label') ?? labelElement.parentElement
    const section = labelContainer?.parentElement
    if (!(section instanceof HTMLElement))
      throw new Error(`Missing section for ${label}`)
    return section
  }

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

  // ================================
  // Rendering Tests
  // ================================
  describe('Rendering', () => {
    it('should render version label', () => {
      renderSelectPackage()

      expect(screen.getByText('plugin.installFromGitHub.selectVersion')).toBeInTheDocument()
    })

    it('should render package label', () => {
      renderSelectPackage()

      expect(screen.getByText('plugin.installFromGitHub.selectPackage')).toBeInTheDocument()
    })

    it('should render back button when not in edit mode', () => {
      renderSelectPackage({ updatePayload: undefined })

      expect(screen.getByRole('button', { name: 'plugin.installModal.back' })).toBeInTheDocument()
    })

    it('should not render back button when in edit mode', () => {
      renderSelectPackage({ updatePayload: createUpdatePayload() })

      expect(screen.queryByRole('button', { name: 'plugin.installModal.back' })).not.toBeInTheDocument()
    })

    it('should render next button', () => {
      renderSelectPackage()

      expect(screen.getByRole('button', { name: 'plugin.installModal.next' })).toBeInTheDocument()
    })
  })

  // ================================
  // Props Tests
  // ================================
  describe('Props', () => {
    it('should pass selectedVersion to PortalSelect', () => {
      renderSelectPackage({ selectedVersion: 'v1.0.0' })

      // PortalSelect should display the selected version
      expect(screen.getAllByText('v1.0.0').length).toBeGreaterThan(0)
    })

    it('should pass selectedPackage to PortalSelect', () => {
      renderSelectPackage({ selectedPackage: 'plugin.zip' })

      expect(screen.getAllByText('plugin.zip').length).toBeGreaterThan(0)
    })

    it('should show installed version badge when updatePayload version differs', () => {
      renderSelectPackage({
        updatePayload: createUpdatePayload(),
        selectedVersion: 'v1.0.0',
      })

      expect(screen.getByText(/v0\.9\.0\s*->\s*v1\.0\.0/)).toBeInTheDocument()
    })
  })

  // ================================
  // Button State Tests
  // ================================
  describe('Button State', () => {
    it('should disable next button when no version selected', () => {
      renderSelectPackage({ selectedVersion: '', selectedPackage: '' })

      expect(screen.getByRole('button', { name: 'plugin.installModal.next' })).toBeDisabled()
    })

    it('should disable next button when version selected but no package', () => {
      renderSelectPackage({ selectedVersion: 'v1.0.0', selectedPackage: '' })

      expect(screen.getByRole('button', { name: 'plugin.installModal.next' })).toBeDisabled()
    })

    it('should enable next button when both version and package selected', () => {
      renderSelectPackage({ selectedVersion: 'v1.0.0', selectedPackage: 'plugin.zip' })

      expect(screen.getByRole('button', { name: 'plugin.installModal.next' })).not.toBeDisabled()
    })
  })

  // ================================
  // User Interactions Tests
  // ================================
  describe('User Interactions', () => {
    it('should call onBack when back button is clicked', () => {
      const onBack = vi.fn()
      renderSelectPackage({ onBack })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.back' }))

      expect(onBack).toHaveBeenCalledTimes(1)
    })

    it('should call handleUploadPackage when next button is clicked', async () => {
      mockHandleUpload.mockImplementation(async (_repo, _version, _package, onSuccess) => {
        onSuccess({ unique_identifier: 'uid', manifest: createMockManifest() })
      })

      const onUploaded = vi.fn()
      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
        onUploaded,
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(mockHandleUpload).toHaveBeenCalledTimes(1)
        expect(mockHandleUpload).toHaveBeenCalledWith(
          'owner/repo',
          'v1.0.0',
          'plugin.zip',
          expect.any(Function),
        )
      })
    })

    it('should not invoke upload when next button is disabled', () => {
      renderSelectPackage({ selectedVersion: '', selectedPackage: '' })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      expect(mockHandleUpload).not.toHaveBeenCalled()
    })

    it('should ignore empty and unknown version selections', () => {
      const onSelectVersion = vi.fn()
      renderSelectPackage({ onSelectVersion })

      const section = getSection('plugin.installFromGitHub.selectVersion')
      fireEvent.click(within(section).getByTestId('select-empty'))
      fireEvent.click(within(section).getByTestId('select-invalid'))

      expect(onSelectVersion).not.toHaveBeenCalled()
    })

    it('should select a valid version option', () => {
      const onSelectVersion = vi.fn()
      renderSelectPackage({ onSelectVersion })

      const section = getSection('plugin.installFromGitHub.selectVersion')
      fireEvent.click(within(section).getByRole('button', { name: 'v0.9.0' }))

      expect(onSelectVersion).toHaveBeenCalledWith({ value: 'v0.9.0', name: 'v0.9.0' })
    })

    it('should ignore empty and unknown package selections', () => {
      const onSelectPackage = vi.fn()
      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        onSelectPackage,
      })

      const section = getSection('plugin.installFromGitHub.selectPackage')
      fireEvent.click(within(section).getByTestId('select-empty'))
      fireEvent.click(within(section).getByTestId('select-invalid'))

      expect(onSelectPackage).not.toHaveBeenCalled()
    })

    it('should select a valid package option', () => {
      const onSelectPackage = vi.fn()
      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        onSelectPackage,
      })

      const section = getSection('plugin.installFromGitHub.selectPackage')
      fireEvent.click(within(section).getByRole('button', { name: 'plugin.tar.gz' }))

      expect(onSelectPackage).toHaveBeenCalledWith({ value: 'plugin.tar.gz', name: 'plugin.tar.gz' })
    })
  })

  // ================================
  // Upload Handling Tests
  // ================================
  describe('Upload Handling', () => {
    it('should call onUploaded with correct data on successful upload', async () => {
      const mockManifest = createMockManifest()
      mockHandleUpload.mockImplementation(async (_repo, _version, _package, onSuccess) => {
        onSuccess({ unique_identifier: 'test-uid', manifest: mockManifest })
      })

      const onUploaded = vi.fn()
      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
        onUploaded,
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(onUploaded).toHaveBeenCalledWith({
          uniqueIdentifier: 'test-uid',
          manifest: mockManifest,
        })
      })
    })

    it('should call onFailed with response message on upload error', async () => {
      mockHandleUpload.mockRejectedValue({ response: { message: 'API Error' } })

      const onFailed = vi.fn()
      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
        onFailed,
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(onFailed).toHaveBeenCalledWith('API Error')
      })
    })

    it('should call onFailed with default message when no response message', async () => {
      mockHandleUpload.mockRejectedValue(new Error('Network error'))

      const onFailed = vi.fn()
      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
        onFailed,
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(onFailed).toHaveBeenCalledWith('plugin.installFromGitHub.uploadFailed')
      })
    })

    it('should not call upload twice when already uploading', async () => {
      let resolveUpload: (value?: unknown) => void
      mockHandleUpload.mockImplementation(() => new Promise((resolve) => {
        resolveUpload = resolve
      }))

      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
      })

      const nextButton = screen.getByRole('button', { name: 'plugin.installModal.next' })

      // Click twice rapidly - this tests the isUploading guard at line 49-50
      // The first click starts the upload, the second should be ignored
      fireEvent.click(nextButton)
      fireEvent.click(nextButton)

      await waitFor(() => {
        expect(mockHandleUpload).toHaveBeenCalledTimes(1)
      })

      // Resolve the upload
      resolveUpload!()
    })

    it('should disable back button while uploading', async () => {
      let resolveUpload: (value?: unknown) => void
      mockHandleUpload.mockImplementation(() => new Promise((resolve) => {
        resolveUpload = resolve
      }))

      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(screen.getByRole('button', { name: 'plugin.installModal.back' })).toBeDisabled()
      })

      resolveUpload!()
    })

    it('should strip github.com prefix from repoUrl', async () => {
      mockHandleUpload.mockResolvedValue({})

      renderSelectPackage({
        repoUrl: 'https://github.com/myorg/myrepo',
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(mockHandleUpload).toHaveBeenCalledWith(
          'myorg/myrepo',
          expect.any(String),
          expect.any(String),
          expect.any(Function),
        )
      })
    })
  })

  // ================================
  // Edge Cases Tests
  // ================================
  describe('Edge Cases', () => {
    it('should handle empty versions array', () => {
      renderSelectPackage({ versions: [] })

      expect(screen.getByText('plugin.installFromGitHub.selectVersion')).toBeInTheDocument()
    })

    it('should handle empty packages array', () => {
      renderSelectPackage({ packages: [] })

      expect(screen.getByText('plugin.installFromGitHub.selectPackage')).toBeInTheDocument()
    })

    it('should handle updatePayload with installed version', () => {
      renderSelectPackage({ updatePayload: createUpdatePayload() })

      // Should not show back button in edit mode
      expect(screen.queryByRole('button', { name: 'plugin.installModal.back' })).not.toBeInTheDocument()
    })

    it('should re-enable buttons after upload completes', async () => {
      mockHandleUpload.mockResolvedValue({})

      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(screen.getByRole('button', { name: 'plugin.installModal.back' })).not.toBeDisabled()
      })
    })

    it('should re-enable buttons after upload fails', async () => {
      mockHandleUpload.mockRejectedValue(new Error('Upload failed'))

      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(screen.getByRole('button', { name: 'plugin.installModal.back' })).not.toBeDisabled()
      })
    })
  })

  // ================================
  // PortalSelect Readonly State Tests
  // ================================
  describe('PortalSelect Readonly State', () => {
    it('should make package select readonly when no version selected', () => {
      renderSelectPackage({ selectedVersion: '' })

      // When no version is selected, package select should be readonly
      const trigger = screen.getAllByTestId('select-trigger')[1]
      expect(trigger).toHaveClass('cursor-not-allowed')
    })

    it('should make package select active when version is selected', () => {
      renderSelectPackage({ selectedVersion: 'v1.0.0' })

      // When version is selected, package select should be active
      const trigger = screen.getAllByTestId('select-trigger')[1]
      expect(trigger).toHaveClass('cursor-pointer')
    })
  })

  // ================================
  // installedValue Props Tests
  // ================================
  describe('installedValue Props', () => {
    it('should pass installedValue when updatePayload is provided', () => {
      const updatePayload = createUpdatePayload()
      renderSelectPackage({ updatePayload })

      // The installed version should be passed to PortalSelect
      // updatePayload.originalPackageInfo.version = 'v0.9.0'
      expect(screen.getByText('plugin.installFromGitHub.selectVersion')).toBeInTheDocument()
    })

    it('should not pass installedValue when updatePayload is undefined', () => {
      renderSelectPackage({ updatePayload: undefined })

      // No installed version indicator
      expect(screen.getByText('plugin.installFromGitHub.selectVersion')).toBeInTheDocument()
    })

    it('should handle updatePayload with different version value', () => {
      const updatePayload = createUpdatePayload()
      updatePayload.originalPackageInfo.version = 'v2.0.0'
      renderSelectPackage({ updatePayload })

      // Should render without errors
      expect(screen.getByText('plugin.installFromGitHub.selectVersion')).toBeInTheDocument()
    })

    it('should show installed badge in version list', () => {
      const updatePayload = createUpdatePayload()
      renderSelectPackage({ updatePayload, selectedVersion: '' })

      fireEvent.click(screen.getByText('plugin.installFromGitHub.selectVersionPlaceholder'))

      expect(screen.getByText('INSTALLED')).toBeInTheDocument()
    })
  })

  // ================================
  // Next Button Disabled State Combinations
  // ================================
  describe('Next Button Disabled State Combinations', () => {
    it('should disable next button when only version is missing', () => {
      renderSelectPackage({ selectedVersion: '', selectedPackage: 'plugin.zip' })

      expect(screen.getByRole('button', { name: 'plugin.installModal.next' })).toBeDisabled()
    })

    it('should disable next button when only package is missing', () => {
      renderSelectPackage({ selectedVersion: 'v1.0.0', selectedPackage: '' })

      expect(screen.getByRole('button', { name: 'plugin.installModal.next' })).toBeDisabled()
    })

    it('should disable next button when both are missing', () => {
      renderSelectPackage({ selectedVersion: '', selectedPackage: '' })

      expect(screen.getByRole('button', { name: 'plugin.installModal.next' })).toBeDisabled()
    })

    it('should disable next button when uploading even with valid selections', async () => {
      let resolveUpload: (value?: unknown) => void
      mockHandleUpload.mockImplementation(() => new Promise((resolve) => {
        resolveUpload = resolve
      }))

      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(screen.getByRole('button', { name: 'plugin.installModal.next' })).toBeDisabled()
      })

      resolveUpload!()
    })
  })

  // ================================
  // RepoUrl Format Handling Tests
  // ================================
  describe('RepoUrl Format Handling', () => {
    it('should handle repoUrl without trailing slash', async () => {
      mockHandleUpload.mockResolvedValue({})

      renderSelectPackage({
        repoUrl: 'https://github.com/owner/repo',
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(mockHandleUpload).toHaveBeenCalledWith(
          'owner/repo',
          'v1.0.0',
          'plugin.zip',
          expect.any(Function),
        )
      })
    })

    it('should handle repoUrl with different org/repo combinations', async () => {
      mockHandleUpload.mockResolvedValue({})

      renderSelectPackage({
        repoUrl: 'https://github.com/my-organization/my-plugin-repo',
        selectedVersion: 'v2.0.0',
        selectedPackage: 'build.tar.gz',
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(mockHandleUpload).toHaveBeenCalledWith(
          'my-organization/my-plugin-repo',
          'v2.0.0',
          'build.tar.gz',
          expect.any(Function),
        )
      })
    })

    it('should pass through repoUrl without github prefix', async () => {
      mockHandleUpload.mockResolvedValue({})

      renderSelectPackage({
        repoUrl: 'plain-org/plain-repo',
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(mockHandleUpload).toHaveBeenCalledWith(
          'plain-org/plain-repo',
          'v1.0.0',
          'plugin.zip',
          expect.any(Function),
        )
      })
    })
  })

  // ================================
  // isEdit Mode Comprehensive Tests
  // ================================
  describe('isEdit Mode Comprehensive', () => {
    it('should set isEdit to true when updatePayload is truthy', () => {
      const updatePayload = createUpdatePayload()
      renderSelectPackage({ updatePayload })

      // Back button should not be rendered in edit mode
      expect(screen.queryByRole('button', { name: 'plugin.installModal.back' })).not.toBeInTheDocument()
    })

    it('should set isEdit to false when updatePayload is undefined', () => {
      renderSelectPackage({ updatePayload: undefined })

      // Back button should be rendered when not in edit mode
      expect(screen.getByRole('button', { name: 'plugin.installModal.back' })).toBeInTheDocument()
    })

    it('should allow upload in edit mode without back button', async () => {
      mockHandleUpload.mockImplementation(async (_repo, _version, _package, onSuccess) => {
        onSuccess({ unique_identifier: 'uid', manifest: createMockManifest() })
      })

      const onUploaded = vi.fn()
      renderSelectPackage({
        updatePayload: createUpdatePayload(),
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
        onUploaded,
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(onUploaded).toHaveBeenCalled()
      })
    })
  })

  // ================================
  // Error Response Handling Tests
  // ================================
  describe('Error Response Handling', () => {
    it('should handle error with response.message property', async () => {
      mockHandleUpload.mockRejectedValue({ response: { message: 'Custom API Error' } })

      const onFailed = vi.fn()
      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
        onFailed,
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(onFailed).toHaveBeenCalledWith('Custom API Error')
      })
    })

    it('should handle error with empty response object', async () => {
      mockHandleUpload.mockRejectedValue({ response: {} })

      const onFailed = vi.fn()
      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
        onFailed,
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(onFailed).toHaveBeenCalledWith('plugin.installFromGitHub.uploadFailed')
      })
    })

    it('should handle error without response property', async () => {
      mockHandleUpload.mockRejectedValue({ code: 'NETWORK_ERROR' })

      const onFailed = vi.fn()
      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
        onFailed,
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(onFailed).toHaveBeenCalledWith('plugin.installFromGitHub.uploadFailed')
      })
    })

    it('should handle error with response but no message', async () => {
      mockHandleUpload.mockRejectedValue({ response: { status: 500 } })

      const onFailed = vi.fn()
      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
        onFailed,
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(onFailed).toHaveBeenCalledWith('plugin.installFromGitHub.uploadFailed')
      })
    })

    it('should handle string error', async () => {
      mockHandleUpload.mockRejectedValue('String error message')

      const onFailed = vi.fn()
      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
        onFailed,
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(onFailed).toHaveBeenCalledWith('plugin.installFromGitHub.uploadFailed')
      })
    })
  })

  // ================================
  // Callback Props Tests
  // ================================
  describe('Callback Props', () => {
    it('should pass onSelectVersion to PortalSelect', () => {
      const onSelectVersion = vi.fn()
      renderSelectPackage({ onSelectVersion })

      // The callback is passed to PortalSelect, which is a base component
      // We verify it's rendered correctly
      expect(screen.getByText('plugin.installFromGitHub.selectVersion')).toBeInTheDocument()
    })

    it('should pass onSelectPackage to PortalSelect', () => {
      const onSelectPackage = vi.fn()
      renderSelectPackage({ onSelectPackage })

      // The callback is passed to PortalSelect, which is a base component
      expect(screen.getByText('plugin.installFromGitHub.selectPackage')).toBeInTheDocument()
    })
  })

  // ================================
  // Upload State Management Tests
  // ================================
  describe('Upload State Management', () => {
    it('should set isUploading to true when upload starts', async () => {
      let resolveUpload: (value?: unknown) => void
      mockHandleUpload.mockImplementation(() => new Promise((resolve) => {
        resolveUpload = resolve
      }))

      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      // Both buttons should be disabled during upload
      await waitFor(() => {
        expect(screen.getByRole('button', { name: 'plugin.installModal.next' })).toBeDisabled()
        expect(screen.getByRole('button', { name: 'plugin.installModal.back' })).toBeDisabled()
      })

      resolveUpload!()
    })

    it('should set isUploading to false after successful upload', async () => {
      mockHandleUpload.mockImplementation(async (_repo, _version, _package, onSuccess) => {
        onSuccess({ unique_identifier: 'uid', manifest: createMockManifest() })
      })

      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(screen.getByRole('button', { name: 'plugin.installModal.next' })).not.toBeDisabled()
        expect(screen.getByRole('button', { name: 'plugin.installModal.back' })).not.toBeDisabled()
      })
    })

    it('should set isUploading to false after failed upload', async () => {
      mockHandleUpload.mockRejectedValue(new Error('Upload failed'))

      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(screen.getByRole('button', { name: 'plugin.installModal.next' })).not.toBeDisabled()
        expect(screen.getByRole('button', { name: 'plugin.installModal.back' })).not.toBeDisabled()
      })
    })

    it('should not allow back button click while uploading', async () => {
      let resolveUpload: (value?: unknown) => void
      mockHandleUpload.mockImplementation(() => new Promise((resolve) => {
        resolveUpload = resolve
      }))

      const onBack = vi.fn()
      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
        onBack,
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(screen.getByRole('button', { name: 'plugin.installModal.back' })).toBeDisabled()
      })

      // Try to click back button while disabled
      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.back' }))

      // onBack should not be called
      expect(onBack).not.toHaveBeenCalled()

      resolveUpload!()
    })
  })

  // ================================
  // handleUpload Callback Tests
  // ================================
  describe('handleUpload Callback', () => {
    it('should invoke onSuccess callback with correct data structure', async () => {
      const mockManifest = createMockManifest()
      mockHandleUpload.mockImplementation(async (_repo, _version, _package, onSuccess) => {
        onSuccess({
          unique_identifier: 'test-unique-identifier',
          manifest: mockManifest,
        })
      })

      const onUploaded = vi.fn()
      renderSelectPackage({
        selectedVersion: 'v1.0.0',
        selectedPackage: 'plugin.zip',
        onUploaded,
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(onUploaded).toHaveBeenCalledWith({
          uniqueIdentifier: 'test-unique-identifier',
          manifest: mockManifest,
        })
      })
    })

    it('should pass correct repo, version, and package to handleUpload', async () => {
      mockHandleUpload.mockResolvedValue({})

      renderSelectPackage({
        repoUrl: 'https://github.com/test-org/test-repo',
        selectedVersion: 'v3.0.0',
        selectedPackage: 'release.zip',
      })

      fireEvent.click(screen.getByRole('button', { name: 'plugin.installModal.next' }))

      await waitFor(() => {
        expect(mockHandleUpload).toHaveBeenCalledWith(
          'test-org/test-repo',
          'v3.0.0',
          'release.zip',
          expect.any(Function),
        )
      })
    })
  })
})
