import type { Mock } from 'vitest'
import type { ModelProvider } from '../declarations'
import { fireEvent, render, screen } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import {
  getStepByStepTourTargetSelector,
  STEP_BY_STEP_TOUR_TARGETS,
} from '@/app/components/step-by-step-tour/target-registry'
import { useMarketplaceAllPlugins } from '../hooks'
import InstallFromMarketplace from '../install-from-marketplace'

// Mock dependencies
vi.mock('@/next/link', () => ({
  default: ({ children, href }: { children: React.ReactNode; href: string }) => (
    <a href={href}>{children}</a>
  ),
}))

vi.mock('@/utils/var', async (importOriginal) => ({
  ...(await importOriginal<typeof import('@/utils/var')>()),
  getMarketplaceUrl: (path = '', params?: Record<string, string | undefined>) => {
    const searchParams = new URLSearchParams()
    Object.entries(params ?? {}).forEach(([key, value]) => {
      if (value !== undefined) searchParams.append(key, value)
    })
    const query = searchParams.toString()
    return `https://marketplace.test${path}${query ? `?${query}` : ''}`
  },
}))

vi.mock('next-themes', () => ({
  useTheme: () => ({ theme: 'light' }),
}))

vi.mock('@/app/components/base/divider', () => ({
  default: () => <div data-testid="divider" />,
}))

vi.mock('@/app/components/base/loading', () => ({
  default: () => <div data-testid="loading" />,
}))

vi.mock('@/app/components/plugins/marketplace/list', () => ({
  default: ({
    plugins,
    cardRender,
  }: {
    plugins: { plugin_id: string; name: string; type?: string }[]
    cardRender: (plugin: { plugin_id: string; name: string; type?: string }) => React.ReactNode
  }) => (
    <div data-testid="plugin-list">
      {plugins.map((p) => (
        <div key={p.plugin_id} data-testid="plugin-item">
          {cardRender(p)}
        </div>
      ))}
    </div>
  ),
}))

vi.mock('@/app/components/plugins/provider-card', () => ({
  default: ({ payload }: { payload: { name: string } }) => <div>{payload.name}</div>,
}))

vi.mock('../hooks', () => ({
  useMarketplaceAllPlugins: vi.fn(() => ({
    plugins: [],
    isLoading: false,
  })),
}))

vi.mock('@/app/components/plugins/plugin-page/use-reference-setting', () => ({
  usePluginSettingsAccess: () => ({
    canInstallPlugin: true,
  }),
}))

describe('InstallFromMarketplace', () => {
  const mockProviders = [] as ModelProvider[]

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

  it('should render expanded by default', () => {
    render(<InstallFromMarketplace providers={mockProviders} searchText="" />)
    expect(screen.getByText('common.modelProvider.installProvider')).toBeInTheDocument()
    expect(screen.getByTestId('plugin-list')).toBeInTheDocument()
  })

  it('should collapse when clicked', () => {
    render(<InstallFromMarketplace providers={mockProviders} searchText="" />)
    const toggle = screen.getByRole('button', { name: /common\.modelProvider\.installProvider/ })

    fireEvent.click(toggle)
    expect(screen.queryByTestId('plugin-list')).not.toBeInTheDocument()
    expect(toggle).toHaveAttribute('aria-expanded', 'false')

    fireEvent.click(toggle)
    expect(toggle).toHaveAttribute('aria-expanded', 'true')
    expect(screen.getByTestId('plugin-list')).toBeInTheDocument()
  })

  it('should show loading state', () => {
    ;(useMarketplaceAllPlugins as unknown as Mock).mockReturnValue({
      plugins: [],
      isLoading: true,
    })

    render(<InstallFromMarketplace providers={mockProviders} searchText="" />)
    // It's expanded by default, so loading should show immediately
    expect(screen.getByTestId('loading')).toBeInTheDocument()
  })

  it('should list plugins', () => {
    ;(useMarketplaceAllPlugins as unknown as Mock).mockReturnValue({
      plugins: [{ plugin_id: '1', name: 'Plugin 1' }],
      isLoading: false,
    })

    render(<InstallFromMarketplace providers={mockProviders} searchText="" />)
    // Expanded by default
    expect(screen.getByText('Plugin 1')).toBeInTheDocument()
  })

  it('should anchor the tour target to the heading and first marketplace row', () => {
    ;(useMarketplaceAllPlugins as unknown as Mock).mockReturnValue({
      plugins: [
        { plugin_id: '1', name: 'Plugin 1' },
        { plugin_id: '2', name: 'Plugin 2' },
        { plugin_id: '3', name: 'Plugin 3' },
        { plugin_id: '4', name: 'Plugin 4' },
      ],
      isLoading: false,
    })

    render(
      <InstallFromMarketplace
        providers={mockProviders}
        searchText=""
        stepByStepTourTarget={STEP_BY_STEP_TOUR_TARGETS.integrationModelProviderInstall}
      />,
    )

    const selector = getStepByStepTourTargetSelector(
      STEP_BY_STEP_TOUR_TARGETS.integrationModelProviderInstall,
    )
    const target = document.querySelector<HTMLElement>(selector)

    expect(target).toHaveClass('absolute', 'inset-x-0', 'top-0', 'h-[174px]')
    expect(target).toHaveAttribute('aria-hidden', 'true')
    expect(target?.parentElement).toContainElement(
      screen.getByRole('button', { name: /common\.modelProvider\.installProvider/ }),
    )
    expect(target?.parentElement).toContainElement(screen.getByTestId('plugin-list'))
  })

  it('should hide bundle plugins from the list', () => {
    ;(useMarketplaceAllPlugins as unknown as Mock).mockReturnValue({
      plugins: [
        { plugin_id: '1', name: 'Plugin 1', type: 'plugin' },
        { plugin_id: '2', name: 'Bundle 1', type: 'bundle' },
      ],
      isLoading: false,
    })

    render(<InstallFromMarketplace providers={mockProviders} searchText="" />)

    expect(screen.getByText('Plugin 1')).toBeInTheDocument()
    expect(screen.queryByText('Bundle 1')).not.toBeInTheDocument()
  })

  it('should render discovery link', () => {
    render(<InstallFromMarketplace providers={mockProviders} searchText="" />)
    expect(screen.getByText('plugin.marketplace.difyMarketplace')).toHaveAttribute(
      'href',
      'https://marketplace.test/plugins/model?theme=light',
    )
  })

  it('should use the marketplace callback action when provided', () => {
    const onOpenMarketplace = vi.fn()

    render(
      <InstallFromMarketplace
        providers={mockProviders}
        searchText=""
        onOpenMarketplace={onOpenMarketplace}
      />,
    )

    fireEvent.click(screen.getByRole('button', { name: 'plugin.marketplace.difyMarketplace' }))

    expect(onOpenMarketplace).toHaveBeenCalledTimes(1)
    expect(
      screen.queryByRole('link', { name: 'plugin.marketplace.difyMarketplace' }),
    ).not.toBeInTheDocument()
  })
})
