import type { LangGeniusVersionInfo } from '@/context/app-context-types'
// Import mocks for assertions
import type { ConsoleStateFixture as BaseConsoleStateFixture } from '@/test/console/state-fixture'
import { toast } from '@langgenius/dify-ui/toast'
import { waitFor } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import {
  useInvalidateReferenceSettings,
  useMutationPluginPermissionSettings,
  useMutationReferenceSettings,
  usePluginAutoUpgradeSettings,
  usePluginPermissionSettings,
} from '@/service/use-plugins'
import { renderHookWithConsoleQuery as renderHook } from '@/test/console/query-data'
import { PermissionType, PluginCategoryEnum } from '../../types'
import useReferenceSetting, { useCanInstallPluginFromMarketplace } from '../use-reference-setting'

const defaultLangGeniusVersionInfo: LangGeniusVersionInfo = {
  current_env: '',
  current_version: '1.0.0',
  latest_version: '',
  release_date: '',
  release_notes: '',
  version: '',
  features: {
    can_replace_logo: false,
    model_load_balancing_enabled: false,
  },
  can_auto_update: false,
}

type ConsoleStateFixture = Omit<BaseConsoleStateFixture, 'langGeniusVersionInfo'> & {
  langGeniusVersionInfo?: Partial<LangGeniusVersionInfo>
}

let mockConsoleState: ConsoleStateFixture = {}

const setConsoleState = (state: ConsoleStateFixture) => {
  mockConsoleState = {
    ...state,
    langGeniusVersionInfo: {
      ...defaultLangGeniusVersionInfo,
      ...state.langGeniusVersionInfo,
    },
  }
}

vi.mock('@/context/workspace-state', async () => {
  const { createWorkspaceStateModuleMock } = await import('@/test/console/state-fixture')
  return createWorkspaceStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/permission-state', async () => {
  const { createPermissionStateModuleMock } = await import('@/test/console/state-fixture')
  return createPermissionStateModuleMock(() => mockConsoleState)
})
vi.mock('@/context/version-state', async () => {
  const { createVersionStateModuleMock } = await import('@/test/console/state-fixture')
  return createVersionStateModuleMock(() => mockConsoleState)
})

vi.mock('@/service/use-plugins', () => ({
  usePluginAutoUpgradeSettings: vi.fn(),
  usePluginPermissionSettings: vi.fn(),
  useMutationPluginPermissionSettings: vi.fn(),
  useMutationReferenceSettings: vi.fn(),
  useInvalidateReferenceSettings: vi.fn(),
}))

const toastSuccessSpy = vi.spyOn(toast, 'success').mockReturnValue('toast-success')

describe('useReferenceSetting Hook', () => {
  beforeEach(() => {
    vi.clearAllMocks()
    toastSuccessSpy.mockClear()

    // Default mocks
    setConsoleState({
      isCurrentWorkspaceManager: false,
      isCurrentWorkspaceOwner: false,
      langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
      workspacePermissionKeys: [] as string[],
    })

    vi.mocked(usePluginAutoUpgradeSettings).mockReturnValue({
      data: {
        category: PluginCategoryEnum.tool,
        auto_upgrade: {
          strategy_setting: 'fix_only',
          upgrade_time_of_day: 0,
          upgrade_mode: 'all',
          exclude_plugins: [],
          include_plugins: [],
        },
      },
    } as unknown as ReturnType<typeof usePluginAutoUpgradeSettings>)

    vi.mocked(usePluginPermissionSettings).mockReturnValue({
      data: {
        install_permission: PermissionType.everyone,
        debug_permission: PermissionType.everyone,
      },
    } as ReturnType<typeof usePluginPermissionSettings>)

    vi.mocked(useMutationReferenceSettings).mockReturnValue({
      mutate: vi.fn(),
      isPending: false,
    } as unknown as ReturnType<typeof useMutationReferenceSettings>)

    vi.mocked(useMutationPluginPermissionSettings).mockReturnValue({
      mutate: vi.fn(),
      isPending: false,
    } as unknown as ReturnType<typeof useMutationPluginPermissionSettings>)

    vi.mocked(useInvalidateReferenceSettings).mockReturnValue(vi.fn())
  })

  describe('permission key access', () => {
    it('should not expose installed plugin list viewing as a permission capability', () => {
      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool))

      expect('canViewInstalledPlugins' in result.current).toBe(false)
    })

    it('should return false without plugin permission keys', () => {
      vi.mocked(usePluginPermissionSettings).mockReturnValue({
        data: {
          install_permission: undefined,
          debug_permission: undefined,
        },
      } as unknown as ReturnType<typeof usePluginPermissionSettings>)

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool))

      expect(result.current.canManagement).toBe(false)
      expect(result.current.canDebugger).toBe(false)
    })

    it('should ignore legacy noOne permission when plugin keys are missing', () => {
      vi.mocked(usePluginPermissionSettings).mockReturnValue({
        data: {
          install_permission: PermissionType.noOne,
          debug_permission: PermissionType.noOne,
        },
      } as ReturnType<typeof usePluginPermissionSettings>)

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool))

      expect(result.current.canManagement).toBe(false)
      expect(result.current.canDebugger).toBe(false)
    })

    it('should allow install and debug when plugin permission keys are present', () => {
      setConsoleState({
        isCurrentWorkspaceManager: false,
        isCurrentWorkspaceOwner: false,
        langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
        workspacePermissionKeys: ['plugin.install', 'plugin.debug'],
      })
      vi.mocked(usePluginPermissionSettings).mockReturnValue({
        data: {
          install_permission: PermissionType.everyone,
          debug_permission: PermissionType.everyone,
        },
      } as ReturnType<typeof usePluginPermissionSettings>)

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool))

      expect(result.current.canManagement).toBe(true)
      expect(result.current.canDebugger).toBe(true)
    })

    it('should allow debug for managers with legacy admin permission when RBAC is disabled', () => {
      setConsoleState({
        isCurrentWorkspaceManager: true,
        isCurrentWorkspaceOwner: false,
        langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
        workspacePermissionKeys: [] as string[],
      })

      vi.mocked(usePluginPermissionSettings).mockReturnValue({
        data: {
          install_permission: PermissionType.admin,
          debug_permission: PermissionType.admin,
        },
      } as ReturnType<typeof usePluginPermissionSettings>)

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool))

      expect(result.current.canManagement).toBe(false)
      expect(result.current.canDebugger).toBe(true)
    })

    it('should allow debug for owners with legacy admin permission when RBAC is disabled', () => {
      setConsoleState({
        isCurrentWorkspaceManager: false,
        isCurrentWorkspaceOwner: true,
        langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
        workspacePermissionKeys: [] as string[],
      })

      vi.mocked(usePluginPermissionSettings).mockReturnValue({
        data: {
          install_permission: PermissionType.admin,
          debug_permission: PermissionType.admin,
        },
      } as ReturnType<typeof usePluginPermissionSettings>)

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool))

      expect(result.current.canManagement).toBe(false)
      expect(result.current.canDebugger).toBe(true)
    })

    it('should allow debug for normal users when legacy debug permission is everyone and RBAC is disabled', () => {
      setConsoleState({
        isCurrentWorkspaceManager: false,
        isCurrentWorkspaceOwner: false,
        langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
        workspacePermissionKeys: ['plugin.install'],
      })

      vi.mocked(usePluginPermissionSettings).mockReturnValue({
        data: {
          install_permission: PermissionType.everyone,
          debug_permission: PermissionType.everyone,
        },
      } as ReturnType<typeof usePluginPermissionSettings>)

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool), {
        systemFeatures: { rbac_enabled: false },
      })

      expect(result.current.canDebugPlugin).toBe(true)
      expect(result.current.canDebugger).toBe(true)
    })

    it('should use plugin keys even when legacy admin permission is configured and RBAC is enabled', () => {
      setConsoleState({
        isCurrentWorkspaceManager: false,
        isCurrentWorkspaceOwner: false,
        langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
        workspacePermissionKeys: ['plugin.install', 'plugin.debug'],
      })

      vi.mocked(usePluginPermissionSettings).mockReturnValue({
        data: {
          install_permission: PermissionType.admin,
          debug_permission: PermissionType.admin,
        },
      } as ReturnType<typeof usePluginPermissionSettings>)

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool), {
        systemFeatures: { rbac_enabled: true },
      })

      expect(result.current.canManagement).toBe(true)
      expect(result.current.canDebugger).toBe(true)
    })

    it('should apply legacy noOne plugin permissions when RBAC is disabled', () => {
      setConsoleState({
        isCurrentWorkspaceManager: true,
        isCurrentWorkspaceOwner: false,
        langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
        workspacePermissionKeys: ['plugin.install', 'plugin.delete', 'plugin.debug'],
      })
      vi.mocked(usePluginPermissionSettings).mockReturnValue({
        data: {
          install_permission: PermissionType.noOne,
          debug_permission: PermissionType.noOne,
        },
      } as ReturnType<typeof usePluginPermissionSettings>)

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool), {
        systemFeatures: { rbac_enabled: false },
      })

      expect(result.current.canInstallPlugin).toBe(false)
      expect(result.current.canManagement).toBe(false)
      expect(result.current.canUpdatePlugin).toBe(false)
      expect(result.current.canDeletePlugin).toBe(false)
      expect(result.current.canDebugPlugin).toBe(false)
      expect(result.current.canDebugger).toBe(false)
    })
  })

  describe('canSetPermissions', () => {
    it('should be true with plugin preferences permission when RBAC is disabled', () => {
      setConsoleState({
        isCurrentWorkspaceManager: false,
        isCurrentWorkspaceOwner: false,
        langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
        workspacePermissionKeys: ['plugin.plugin_preferences'],
      })

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool))

      expect(result.current.canSetPermissions).toBe(true)
    })

    it('should be false when RBAC is enabled even with plugin preferences permission', () => {
      setConsoleState({
        isCurrentWorkspaceManager: false,
        isCurrentWorkspaceOwner: true,
        langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
        workspacePermissionKeys: ['plugin.plugin_preferences'],
      })

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool), {
        systemFeatures: { rbac_enabled: true },
      })

      expect(result.current.canSetPermissions).toBe(false)
      expect(result.current.canSetPluginPreferences).toBe(true)
    })

    it('should be false without plugin preferences permission', () => {
      setConsoleState({
        isCurrentWorkspaceManager: true,
        isCurrentWorkspaceOwner: false,
        langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
        workspacePermissionKeys: [] as string[],
      })

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool))

      expect(result.current.canSetPermissions).toBe(false)
    })
  })

  describe('setReferenceSettings callback', () => {
    it('should call invalidateReferenceSettings and show toast on success', async () => {
      const mockInvalidate = vi.fn()
      vi.mocked(useInvalidateReferenceSettings).mockReturnValue(mockInvalidate)

      let onSuccessCallback: (() => void) | undefined
      vi.mocked(useMutationReferenceSettings).mockImplementation((options) => {
        onSuccessCallback = options?.onSuccess as () => void
        return {
          mutate: vi.fn(),
          isPending: false,
        } as unknown as ReturnType<typeof useMutationReferenceSettings>
      })

      renderHook(() => useReferenceSetting(PluginCategoryEnum.tool))

      // Trigger the onSuccess callback
      if (onSuccessCallback) onSuccessCallback()

      await waitFor(() => {
        expect(mockInvalidate).toHaveBeenCalled()
        expect(toastSuccessSpy).toHaveBeenCalledWith('common.api.actionSuccess')
      })
    })
  })

  describe('returned values', () => {
    it('should return referenceSetting data', () => {
      const mockData = {
        permission: {
          install_permission: PermissionType.everyone,
          debug_permission: PermissionType.everyone,
        },
        auto_upgrade: {
          strategy_setting: 'fix_only',
          upgrade_time_of_day: 0,
          upgrade_mode: 'all',
          exclude_plugins: [],
          include_plugins: [],
        },
      }
      vi.mocked(usePluginAutoUpgradeSettings).mockReturnValue({
        data: {
          category: PluginCategoryEnum.tool,
          auto_upgrade: mockData.auto_upgrade,
        },
      } as unknown as ReturnType<typeof usePluginAutoUpgradeSettings>)

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool))

      expect(result.current.referenceSetting).toEqual(mockData)
    })

    it('should return isUpdatePending from mutation', () => {
      vi.mocked(useMutationReferenceSettings).mockReturnValue({
        mutate: vi.fn(),
        isPending: true,
      } as unknown as ReturnType<typeof useMutationReferenceSettings>)

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool))

      expect(result.current.isUpdatePending).toBe(true)
    })

    it('should keep permission key access available when reference setting data is still loading', () => {
      setConsoleState({
        isCurrentWorkspaceManager: false,
        isCurrentWorkspaceOwner: false,
        langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
        workspacePermissionKeys: ['plugin.install', 'plugin.debug'],
      })
      vi.mocked(usePluginAutoUpgradeSettings).mockReturnValue({
        data: undefined,
      } as unknown as ReturnType<typeof usePluginAutoUpgradeSettings>)

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool))

      expect(result.current.referenceSetting).toBeUndefined()
      expect(result.current.canManagement).toBe(true)
      expect(result.current.canDebugger).toBe(true)
    })

    it('should keep permission state loading while workspace permission keys are loading', () => {
      setConsoleState({
        isCurrentWorkspaceManager: false,
        isCurrentWorkspaceOwner: false,
        isLoadingWorkspacePermissionKeys: true,
        langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
        workspacePermissionKeys: [] as string[],
      })

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool))

      expect(result.current.isPermissionLoading).toBe(true)
      expect(result.current.canInstallPlugin).toBe(false)
    })

    it('should keep permission state loading while current workspace is loading', () => {
      setConsoleState({
        isCurrentWorkspaceManager: false,
        isCurrentWorkspaceOwner: false,
        isLoadingCurrentWorkspace: true,
        langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
        workspacePermissionKeys: ['plugin.install'],
      })

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool))

      expect(result.current.isPermissionLoading).toBe(true)
    })
  })

  describe('RBAC permissions', () => {
    it('should use workspace permission keys when RBAC is enabled', () => {
      setConsoleState({
        isCurrentWorkspaceManager: false,
        isCurrentWorkspaceOwner: false,
        langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
        workspacePermissionKeys: [
          'plugin.install',
          'plugin.delete',
          'plugin.debug',
          'plugin.plugin_preferences',
        ],
      })
      vi.mocked(usePluginPermissionSettings).mockReturnValue({
        data: {
          install_permission: PermissionType.noOne,
          debug_permission: PermissionType.noOne,
        },
      } as ReturnType<typeof usePluginPermissionSettings>)

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool), {
        systemFeatures: { rbac_enabled: true },
      })

      expect(result.current.canInstallPlugin).toBe(true)
      expect(result.current.canManagement).toBe(true)
      expect(result.current.canUpdatePlugin).toBe(true)
      expect(result.current.canDeletePlugin).toBe(true)
      expect(result.current.canDebugPlugin).toBe(true)
      expect(result.current.canDebugger).toBe(true)
      expect(result.current.canSetPermissions).toBe(false)
      expect(result.current.canSetPluginPreferences).toBe(true)
    })

    it('should ignore legacy plugin permission settings when RBAC is enabled', () => {
      setConsoleState({
        isCurrentWorkspaceManager: true,
        isCurrentWorkspaceOwner: false,
        langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
        workspacePermissionKeys: [] as string[],
      })

      const { result } = renderHook(() => useReferenceSetting(PluginCategoryEnum.tool), {
        systemFeatures: { rbac_enabled: true },
      })

      expect(result.current.canInstallPlugin).toBe(false)
      expect(result.current.canManagement).toBe(false)
      expect(result.current.canUpdatePlugin).toBe(false)
      expect(result.current.canDeletePlugin).toBe(false)
      expect(result.current.canDebugPlugin).toBe(false)
      expect(result.current.canDebugger).toBe(false)
      expect(result.current.canSetPermissions).toBe(false)
      expect(result.current.canSetPluginPreferences).toBe(false)
    })
  })
})

describe('useCanInstallPluginFromMarketplace Hook', () => {
  beforeEach(() => {
    vi.clearAllMocks()

    setConsoleState({
      isCurrentWorkspaceManager: true,
      isCurrentWorkspaceOwner: false,
      langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
      workspacePermissionKeys: ['plugin.install'],
    })

    vi.mocked(usePluginPermissionSettings).mockReturnValue({
      data: {
        install_permission: PermissionType.everyone,
        debug_permission: PermissionType.everyone,
      },
    } as ReturnType<typeof usePluginPermissionSettings>)

    vi.mocked(useMutationReferenceSettings).mockReturnValue({
      mutate: vi.fn(),
      isPending: false,
    } as unknown as ReturnType<typeof useMutationReferenceSettings>)

    vi.mocked(useInvalidateReferenceSettings).mockReturnValue(vi.fn())
  })

  it('should return true when marketplace is enabled and plugin.install is available', () => {
    const { result } = renderHook(() => useCanInstallPluginFromMarketplace(), {
      systemFeatures: { enable_marketplace: true },
    })

    expect(result.current.canInstallPluginFromMarketplace).toBe(true)
  })

  it('should return false when marketplace is disabled', () => {
    const { result } = renderHook(() => useCanInstallPluginFromMarketplace(), {
      systemFeatures: { enable_marketplace: false },
    })

    expect(result.current.canInstallPluginFromMarketplace).toBe(false)
  })

  it('should return false without plugin.install', () => {
    setConsoleState({
      isCurrentWorkspaceManager: true,
      isCurrentWorkspaceOwner: false,
      langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
      workspacePermissionKeys: [] as string[],
    })

    const { result } = renderHook(() => useCanInstallPluginFromMarketplace(), {
      systemFeatures: { enable_marketplace: true },
    })

    expect(result.current.canInstallPluginFromMarketplace).toBe(false)
  })

  it('should return false when both marketplace is disabled and plugin.install is missing', () => {
    setConsoleState({
      isCurrentWorkspaceManager: true,
      isCurrentWorkspaceOwner: false,
      langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
      workspacePermissionKeys: [] as string[],
    })

    const { result } = renderHook(() => useCanInstallPluginFromMarketplace(), {
      systemFeatures: { enable_marketplace: false },
    })

    expect(result.current.canInstallPluginFromMarketplace).toBe(false)
  })

  it('should fetch legacy plugin permissions but not category auto-upgrade settings', () => {
    renderHook(() => useCanInstallPluginFromMarketplace(), {
      systemFeatures: { enable_marketplace: true },
    })

    expect(usePluginPermissionSettings).toHaveBeenCalled()
    expect(usePluginAutoUpgradeSettings).not.toHaveBeenCalled()
  })

  it('should return false when legacy install permission is noOne and RBAC is disabled', () => {
    vi.mocked(usePluginPermissionSettings).mockReturnValue({
      data: {
        install_permission: PermissionType.noOne,
        debug_permission: PermissionType.everyone,
      },
    } as ReturnType<typeof usePluginPermissionSettings>)

    const { result } = renderHook(() => useCanInstallPluginFromMarketplace(), {
      systemFeatures: {
        enable_marketplace: true,
        rbac_enabled: false,
      },
    })

    expect(result.current.canInstallPluginFromMarketplace).toBe(false)
  })

  it('should use plugin.install when marketplace and RBAC are enabled', () => {
    setConsoleState({
      isCurrentWorkspaceManager: false,
      isCurrentWorkspaceOwner: false,
      langGeniusVersionInfo: { current_version: '1.0.0', latest_version: '', version: '' },
      workspacePermissionKeys: ['plugin.install'],
    })
    vi.mocked(usePluginPermissionSettings).mockReturnValue({
      data: {
        install_permission: PermissionType.noOne,
        debug_permission: PermissionType.noOne,
      },
    } as ReturnType<typeof usePluginPermissionSettings>)

    const { result } = renderHook(() => useCanInstallPluginFromMarketplace(), {
      systemFeatures: {
        enable_marketplace: true,
        rbac_enabled: true,
      },
    })

    expect(result.current.canInstallPluginFromMarketplace).toBe(true)
  })
})
