import type { DataSourceNodeType } from '../nodes/data-source/types'
import type { ToolNodeType } from '../nodes/tool/types'
import type { PluginTriggerNodeType } from '../nodes/trigger-plugin/types'
import type { CommonNodeType } from '../types'
import { useCallback, useMemo } from 'react'
import useWorkspacePluginInstallPermission from '@/app/components/plugins/install-plugin/hooks/use-workspace-plugin-install-permission'
import { CollectionType } from '@/app/components/tools/types'
import { useInvalidDataSourceList } from '@/service/use-pipeline'
import {
  useAllBuiltInTools,
  useAllCustomTools,
  useAllMCPTools,
  useAllWorkflowTools,
  useInvalidToolsByType,
} from '@/service/use-tools'
import { useAllTriggerPlugins, useInvalidateAllTriggerPlugins } from '@/service/use-triggers'
import { useStore } from '../store'
import { BlockEnum } from '../types'
import {
  matchDataSource,
  matchToolInCollection,
  matchTriggerProvider,
} from '../utils/plugin-install-check'

type InstallationState = {
  isChecking: boolean
  isMissing: boolean
  uniqueIdentifier?: string
  canInstall: boolean
  onInstallSuccess: () => void
  shouldDim: boolean
}

const NOOP_INSTALLATION: InstallationState = {
  isChecking: false,
  isMissing: false,
  uniqueIdentifier: undefined,
  canInstall: false,
  onInstallSuccess: () => undefined,
  shouldDim: false,
}

const useToolInstallation = (
  data: ToolNodeType,
  enabled: boolean,
  canInstallPlugin: boolean,
): InstallationState => {
  const isBuiltIn = enabled && data.provider_type === CollectionType.builtIn
  const isCustom = enabled && data.provider_type === CollectionType.custom
  const isWorkflow = enabled && data.provider_type === CollectionType.workflow
  const isMcp = enabled && data.provider_type === CollectionType.mcp

  const builtInQuery = useAllBuiltInTools(isBuiltIn)
  const customQuery = useAllCustomTools(isCustom)
  const workflowQuery = useAllWorkflowTools(isWorkflow)
  const mcpQuery = useAllMCPTools(isMcp)
  const invalidateTools = useInvalidToolsByType(enabled ? data.provider_type : undefined)

  const collectionInfo = useMemo(() => {
    if (!enabled) return undefined

    switch (data.provider_type) {
      case CollectionType.builtIn:
        return {
          list: builtInQuery.data,
          isLoading: builtInQuery.isLoading,
        }
      case CollectionType.custom:
        return {
          list: customQuery.data,
          isLoading: customQuery.isLoading,
        }
      case CollectionType.workflow:
        return {
          list: workflowQuery.data,
          isLoading: workflowQuery.isLoading,
        }
      case CollectionType.mcp:
        return {
          list: mcpQuery.data,
          isLoading: mcpQuery.isLoading,
        }
      default:
        return undefined
    }
  }, [
    enabled,
    builtInQuery.data,
    builtInQuery.isLoading,
    customQuery.data,
    customQuery.isLoading,
    data.provider_type,
    mcpQuery.data,
    mcpQuery.isLoading,
    workflowQuery.data,
    workflowQuery.isLoading,
  ])

  const collection = collectionInfo?.list
  const isLoading = collectionInfo?.isLoading ?? false
  const isResolved = !!collectionInfo && !isLoading

  const { plugin_id, provider_id, provider_name } = data
  const matchedCollection = useMemo(() => {
    if (!collection || !collection.length) return undefined

    return matchToolInCollection(collection, { plugin_id, provider_id, provider_name })
  }, [collection, plugin_id, provider_id, provider_name])

  const uniqueIdentifier = data.plugin_unique_identifier || data.plugin_id || data.provider_id
  const canInstall = Boolean(data.plugin_unique_identifier) && canInstallPlugin

  const onInstallSuccess = useCallback(() => {
    if (invalidateTools) invalidateTools()
  }, [invalidateTools])

  const shouldDim = (!!collectionInfo && !isResolved) || (isResolved && !matchedCollection)

  return {
    isChecking: !!collectionInfo && !isResolved,
    isMissing: isResolved && !matchedCollection,
    uniqueIdentifier,
    canInstall,
    onInstallSuccess,
    shouldDim,
  }
}

const useTriggerInstallation = (
  data: PluginTriggerNodeType,
  enabled: boolean,
  canInstallPlugin: boolean,
): InstallationState => {
  const triggerPluginsQuery = useAllTriggerPlugins(enabled)
  const invalidateTriggers = useInvalidateAllTriggerPlugins()

  const triggerProviders = triggerPluginsQuery.data
  const isLoading = triggerPluginsQuery.isLoading

  const { plugin_id, provider_id, provider_name } = data
  const matchedProvider = useMemo(() => {
    if (!triggerProviders || !triggerProviders.length) return undefined

    return matchTriggerProvider(triggerProviders, { plugin_id, provider_id, provider_name })
  }, [plugin_id, provider_id, provider_name, triggerProviders])

  const uniqueIdentifier = data.plugin_unique_identifier || data.plugin_id || data.provider_id
  const canInstall = Boolean(data.plugin_unique_identifier) && canInstallPlugin

  const onInstallSuccess = useCallback(() => {
    invalidateTriggers()
  }, [invalidateTriggers])

  const shouldDim = isLoading || (!isLoading && !!triggerProviders && !matchedProvider)

  return {
    isChecking: isLoading,
    isMissing: !isLoading && !!triggerProviders && !matchedProvider,
    uniqueIdentifier,
    canInstall,
    onInstallSuccess,
    shouldDim,
  }
}

const useDataSourceInstallation = (
  data: DataSourceNodeType,
  _enabled: boolean,
  canInstallPlugin: boolean,
): InstallationState => {
  const dataSourceList = useStore((s) => s.dataSourceList)
  const invalidateDataSourceList = useInvalidDataSourceList()

  const { plugin_unique_identifier, plugin_id, provider_name } = data
  const matchedPlugin = useMemo(() => {
    if (!dataSourceList || !dataSourceList.length) return undefined

    return matchDataSource(dataSourceList, { plugin_unique_identifier, plugin_id, provider_name })
  }, [dataSourceList, plugin_id, plugin_unique_identifier, provider_name])

  const uniqueIdentifier = data.plugin_unique_identifier || data.plugin_id
  const canInstall = Boolean(data.plugin_unique_identifier) && canInstallPlugin

  const onInstallSuccess = useCallback(() => {
    invalidateDataSourceList()
  }, [invalidateDataSourceList])

  const hasLoadedList = dataSourceList !== undefined

  const shouldDim = !hasLoadedList || (hasLoadedList && !matchedPlugin)

  return {
    isChecking: !hasLoadedList,
    isMissing: hasLoadedList && !matchedPlugin,
    uniqueIdentifier,
    canInstall,
    onInstallSuccess,
    shouldDim,
  }
}

export const useNodePluginInstallation = (data: CommonNodeType): InstallationState => {
  const isTool = data.type === BlockEnum.Tool
  const isTrigger = data.type === BlockEnum.TriggerPlugin
  const isDataSource = data.type === BlockEnum.DataSource
  const { canInstallPlugin } = useWorkspacePluginInstallPermission()

  const toolInstallation = useToolInstallation(data as ToolNodeType, isTool, canInstallPlugin)
  const triggerInstallation = useTriggerInstallation(
    data as PluginTriggerNodeType,
    isTrigger,
    canInstallPlugin,
  )
  const dataSourceInstallation = useDataSourceInstallation(
    data as DataSourceNodeType,
    isDataSource,
    canInstallPlugin,
  )

  if (isTool) return toolInstallation
  if (isTrigger) return triggerInstallation
  if (isDataSource) return dataSourceInstallation

  return NOOP_INSTALLATION
}
