import type { TriggerSubscriptionBuilder } from '@/app/components/workflow/block-selector/types'
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
import { Select, SelectContent, SelectItem, SelectItemIndicator, SelectTrigger } from '@langgenius/dify-ui/select'
import { toast } from '@langgenius/dify-ui/toast'
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import { useBoolean } from 'ahooks'
import { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { ActionButton, ActionButtonState } from '@/app/components/base/action-button'
import Badge from '@/app/components/base/badge'
import { Infotip } from '@/app/components/base/infotip'
import { openOAuthPopup } from '@/hooks/use-oauth'
import { useInitiateTriggerOAuth, useTriggerOAuthConfig, useTriggerProviderInfo } from '@/service/use-triggers'
import { SupportedCreationMethods } from '../../../types'
import { usePluginStore } from '../../store'
import { useSubscriptionList } from '../use-subscription-list'
import { CommonCreateModal } from './common-modal'
import { OAuthClientSettingsModal } from './oauth-client'
import { CreateButtonType, DEFAULT_METHOD } from './types'

type Props = Readonly<{
  className?: string
  buttonType?: CreateButtonType
  shape?: 'square' | 'circle'
}>

const MAX_COUNT = 10

type CreateTypeOption = {
  value: SupportedCreationMethods
  label: string
  show: boolean
  extra?: React.ReactNode
  tag?: React.ReactNode
}

export const CreateSubscriptionButton = ({ buttonType = CreateButtonType.FULL_BUTTON, shape = 'square' }: Props) => {
  const { t } = useTranslation()
  const { subscriptions } = useSubscriptionList()
  const subscriptionCount = subscriptions?.length || 0
  const [selectedCreateInfo, setSelectedCreateInfo] = useState<{ type: SupportedCreationMethods, builder?: TriggerSubscriptionBuilder } | null>(null)
  const [isCreateModalOpen, setIsCreateModalOpen] = useState(false)

  const detail = usePluginStore(state => state.detail)
  const [isMenuOpen, setIsMenuOpen] = useState(false)

  const { data: providerInfo } = useTriggerProviderInfo(detail?.provider || '')
  const supportedMethods = useMemo(() => providerInfo?.supported_creation_methods || [], [providerInfo?.supported_creation_methods])
  const { data: oauthConfig, refetch: refetchOAuthConfig } = useTriggerOAuthConfig(detail?.provider || '', supportedMethods.includes(SupportedCreationMethods.OAUTH))
  const { mutate: initiateOAuth } = useInitiateTriggerOAuth()

  const methodType = supportedMethods.length === 1 ? supportedMethods[0] : DEFAULT_METHOD

  const [isShowClientSettingsModal, {
    setTrue: showClientSettingsModal,
    setFalse: hideClientSettingsModal,
  }] = useBoolean(false)

  const buttonTextMap = useMemo(() => {
    return {
      [SupportedCreationMethods.OAUTH]: t('subscription.createButton.oauth', { ns: 'pluginTrigger' }),
      [SupportedCreationMethods.APIKEY]: t('subscription.createButton.apiKey', { ns: 'pluginTrigger' }),
      [SupportedCreationMethods.MANUAL]: t('subscription.createButton.manual', { ns: 'pluginTrigger' }),
      [DEFAULT_METHOD]: t('subscription.empty.button', { ns: 'pluginTrigger' }),
    }
  }, [t])

  const onClickClientSettings = useCallback((e: React.MouseEvent<HTMLDivElement | HTMLButtonElement>) => {
    e.stopPropagation()
    e.preventDefault()
    setIsMenuOpen(false)
    showClientSettingsModal()
  }, [showClientSettingsModal])

  const handleClientSettingsOpenChange = useCallback((open: boolean) => {
    if (open) {
      showClientSettingsModal()
      return
    }

    hideClientSettingsModal()
    refetchOAuthConfig()
  }, [hideClientSettingsModal, refetchOAuthConfig, showClientSettingsModal])

  const allOptions = useMemo<CreateTypeOption[]>(() => {
    const showCustomBadge = oauthConfig?.custom_enabled && oauthConfig?.custom_configured

    return [
      {
        value: SupportedCreationMethods.OAUTH,
        label: t('subscription.addType.options.oauth.title', { ns: 'pluginTrigger' }),
        tag: !showCustomBadge
          ? null
          : (
              <Badge className="mr-0.5 ml-1">
                {t('auth.custom', { ns: 'plugin' })}
              </Badge>
            ),
        extra: (
          <Tooltip>
            <TooltipTrigger
              render={(
                <ActionButton
                  aria-label={t('subscription.addType.options.oauth.clientSettings', { ns: 'pluginTrigger' })}
                  onClick={onClickClientSettings}
                >
                  <span aria-hidden className="i-ri-equalizer-2-line size-4 text-text-tertiary" />
                </ActionButton>
              )}
            />
            <TooltipContent>
              {t('subscription.addType.options.oauth.clientSettings', { ns: 'pluginTrigger' })}
            </TooltipContent>
          </Tooltip>
        ),
        show: supportedMethods.includes(SupportedCreationMethods.OAUTH),
      },
      {
        value: SupportedCreationMethods.APIKEY,
        label: t('subscription.addType.options.apikey.title', { ns: 'pluginTrigger' }),
        show: supportedMethods.includes(SupportedCreationMethods.APIKEY),
      },
      {
        value: SupportedCreationMethods.MANUAL,
        label: t('subscription.addType.options.manual.description', { ns: 'pluginTrigger' }),
        extra: (
          <Infotip
            aria-label={t('subscription.addType.options.manual.tip', { ns: 'pluginTrigger' })}
            className="size-3.5"
            iconClassName="h-full w-full"
          >
            {t('subscription.addType.options.manual.tip', { ns: 'pluginTrigger' })}
          </Infotip>
        ),
        show: supportedMethods.includes(SupportedCreationMethods.MANUAL),
      },
    ]
  }, [t, oauthConfig, supportedMethods, onClickClientSettings])
  const visibleOptions = useMemo(() => {
    return allOptions.filter(option => option.show)
  }, [allOptions])
  const shouldAllowSelect = methodType === DEFAULT_METHOD || (methodType === SupportedCreationMethods.OAUTH && supportedMethods.length === 1)

  const showCreateModal = useCallback((createInfo: { type: SupportedCreationMethods, builder?: TriggerSubscriptionBuilder }) => {
    setSelectedCreateInfo(createInfo)
    setIsCreateModalOpen(true)
  }, [])

  const hideCreateModal = useCallback(() => {
    setIsCreateModalOpen(false)
  }, [])

  const onChooseCreateType = async (type: SupportedCreationMethods) => {
    if (type === SupportedCreationMethods.OAUTH) {
      if (oauthConfig?.configured) {
        initiateOAuth(detail?.provider || '', {
          onSuccess: (response) => {
            openOAuthPopup(response.authorization_url, (callbackData) => {
              if (callbackData) {
                toast.success(t('modal.oauth.authorization.authSuccess', { ns: 'pluginTrigger' }))
                showCreateModal({
                  type: SupportedCreationMethods.OAUTH,
                  builder: response.subscription_builder,
                })
              }
            })
          },
          onError: () => {
            toast.error(t('modal.oauth.authorization.authFailed', { ns: 'pluginTrigger' }))
          },
        })
      }
      else {
        showClientSettingsModal()
      }
    }
    else {
      showCreateModal({
        type,
      })
    }
  }

  const handleCreateTypeChange = (value: string | null) => {
    const option = visibleOptions.find(item => item.value === value)
    if (!option)
      return

    setIsMenuOpen(false)
    void onChooseCreateType(option.value)
  }

  const onClickCreate = (e: React.MouseEvent<HTMLButtonElement>) => {
    if (subscriptionCount >= MAX_COUNT) {
      e.stopPropagation()
      return
    }

    if (methodType === DEFAULT_METHOD || (methodType === SupportedCreationMethods.OAUTH && supportedMethods.length === 1))
      return

    e.stopPropagation()
    e.preventDefault()
    onChooseCreateType(methodType!)
  }

  if (!supportedMethods.length)
    return null

  return (
    <>
      <Select
        value={methodType === DEFAULT_METHOD ? null : methodType}
        open={shouldAllowSelect ? isMenuOpen : false}
        onOpenChange={setIsMenuOpen}
        onValueChange={handleCreateTypeChange}
      >
        <SelectTrigger
          render={<div />}
          nativeButton={false}
          className={cn('h-8 border-0 bg-transparent px-0 hover:bg-transparent focus-visible:bg-transparent [&>*:last-child]:hidden', buttonType === CreateButtonType.FULL_BUTTON && 'grow')}
        >
          {buttonType === CreateButtonType.FULL_BUTTON
            ? (
                <Button
                  variant="primary"
                  size="medium"
                  className="flex w-full items-center justify-between px-0"
                  onClick={onClickCreate}
                >
                  <div className="flex flex-1 items-center justify-center">
                    <span aria-hidden className="mr-2 i-ri-add-line size-4" />
                    {buttonTextMap[methodType!]}
                    {methodType === SupportedCreationMethods.OAUTH && oauthConfig?.custom_enabled && oauthConfig?.custom_configured && (
                      <Badge
                        className="mr-0.5 ml-1 border-text-primary-on-surface bg-components-badge-bg-dimm text-text-primary-on-surface"
                      >
                        {t('auth.custom', { ns: 'plugin' })}
                      </Badge>
                    )}
                  </div>
                  {methodType === SupportedCreationMethods.OAUTH
                    && (
                      <div className="ml-auto flex items-center">
                        <div className="h-4 w-px bg-text-primary-on-surface opacity-15" />
                        <Tooltip>
                          <TooltipTrigger
                            render={(
                              <div onClick={onClickClientSettings} className="p-2">
                                <span aria-hidden className="i-ri-equalizer-2-line size-4 text-components-button-primary-text" />
                              </div>
                            )}
                          />
                          <TooltipContent>
                            {t('subscription.addType.options.oauth.clientSettings', { ns: 'pluginTrigger' })}
                          </TooltipContent>
                        </Tooltip>
                      </div>
                    )}
                </Button>
              )
            : (
                <Tooltip>
                  <TooltipTrigger
                    disabled={!(supportedMethods?.length === 1 || subscriptionCount >= MAX_COUNT)}
                    render={(
                      <ActionButton
                        aria-label={buttonTextMap[methodType!]}
                        onClick={onClickCreate}
                        className={cn(
                          'float-right',
                          shape === 'circle' && 'rounded-full! border-[0.5px] border-components-button-secondary-border-hover bg-components-button-secondary-bg-hover text-components-button-secondary-accent-text shadow-xs hover:border-components-button-secondary-border-disabled hover:bg-components-button-secondary-bg-disabled hover:text-components-button-secondary-accent-text-disabled',
                        )}
                        state={subscriptionCount >= MAX_COUNT ? ActionButtonState.Disabled : ActionButtonState.Default}
                      >
                        <span aria-hidden className="i-ri-add-line size-4" />
                      </ActionButton>
                    )}
                  />
                  <TooltipContent>
                    {subscriptionCount >= MAX_COUNT ? t('subscription.maxCount', { ns: 'pluginTrigger', num: MAX_COUNT }) : t(`subscription.addType.options.${methodType!.toLowerCase() as Lowercase<SupportedCreationMethods>}.description`, { ns: 'pluginTrigger' })}
                  </TooltipContent>
                </Tooltip>
              )}
        </SelectTrigger>
        <SelectContent placement="bottom-start" sideOffset={4}>
          {visibleOptions.map(option => (
            <SelectItem key={option.value} value={option.value}>
              <div className="mr-8 flex grow items-center gap-1 truncate px-1">
                {option.label}
                {option.tag}
              </div>
              {option.extra}
              <SelectItemIndicator />
            </SelectItem>
          ))}
        </SelectContent>
      </Select>
      {selectedCreateInfo
        ? (
            <CommonCreateModal
              open={isCreateModalOpen}
              createType={selectedCreateInfo.type}
              builder={selectedCreateInfo.builder}
              onClose={hideCreateModal}
            />
          )
        : null}
      {isShowClientSettingsModal
        ? (
            <OAuthClientSettingsModal
              open={isShowClientSettingsModal}
              oauthConfig={oauthConfig}
              onOpenChange={handleClientSettingsOpenChange}
              showOAuthCreateModal={(builder) => {
                showCreateModal({
                  type: SupportedCreationMethods.OAUTH,
                  builder,
                })
              }}
            />
          )
        : null}
    </>
  )
}
