'use client'
import type { FormRefObject, FormSchema } from '@/app/components/base/form/types'
import type { ParametersSchema, PluginDetail } from '@/app/components/plugins/types'
import type { TriggerSubscription } from '@/app/components/workflow/block-selector/types'
import { Button } from '@langgenius/dify-ui/button'
import { Dialog, DialogCloseButton, DialogContent, DialogTitle } from '@langgenius/dify-ui/dialog'
import { toast } from '@langgenius/dify-ui/toast'
import { isEqual } from 'es-toolkit/predicate'
import { useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { EncryptedBottom } from '@/app/components/base/encrypted-bottom'
import { BaseForm } from '@/app/components/base/form/components/base'
import { FormTypeEnum } from '@/app/components/base/form/types'
import { ReadmeEntrance } from '@/app/components/plugins/readme-panel/entrance'
import { useUpdateTriggerSubscription, useVerifyTriggerSubscription } from '@/service/use-triggers'
import { parsePluginErrorMessage } from '@/utils/error-parser'
import { usePluginStore } from '../../store'
import { useSubscriptionList } from '../use-subscription-list'

type Props = {
  onClose: () => void
  subscription: TriggerSubscription
  pluginDetail?: PluginDetail
}

const EditStep = {
  EditCredentials: 'edit_credentials',
  EditConfiguration: 'edit_configuration',
} as const

type EditStep = typeof EditStep[keyof typeof EditStep]

const normalizeFormType = (type: string): FormTypeEnum => {
  switch (type) {
    case 'string':
    case 'text':
      return FormTypeEnum.textInput
    case 'password':
    case 'secret':
      return FormTypeEnum.secretInput
    case 'number':
    case 'integer':
      return FormTypeEnum.textNumber
    case 'boolean':
      return FormTypeEnum.boolean
    case 'select':
      return FormTypeEnum.select
    default:
      if (Object.values(FormTypeEnum).includes(type as FormTypeEnum))
        return type as FormTypeEnum
      return FormTypeEnum.textInput
  }
}

const HIDDEN_SECRET_VALUE = '[__HIDDEN__]'

const areAllCredentialsHidden = (credentials: Record<string, unknown>): boolean => {
  return Object.values(credentials).every(value => value === HIDDEN_SECRET_VALUE)
}

const StatusStep = ({ isActive, text, onClick, clickable }: {
  isActive: boolean
  text: string
  onClick?: () => void
  clickable?: boolean
}) => {
  const className = `flex items-center gap-1 system-2xs-semibold-uppercase ${isActive
    ? 'text-state-accent-solid'
    : 'text-text-tertiary'} ${clickable ? 'cursor-pointer rounded bg-transparent p-0 text-left hover:text-text-secondary focus-visible:text-text-secondary focus-visible:ring-1 focus-visible:ring-components-input-border-hover focus-visible:outline-hidden' : ''}`

  const content = (
    <>
      {isActive
        ? (
            <div className="size-1 rounded-full bg-state-accent-solid"></div>
          )
        : null}
      {text}
    </>
  )

  if (clickable) {
    return (
      <button
        type="button"
        className={className}
        onClick={onClick}
      >
        {content}
      </button>
    )
  }

  return (
    <div className={className}>
      {content}
    </div>
  )
}

const MultiSteps = ({ currentStep, onStepClick }: { currentStep: EditStep, onStepClick?: (step: EditStep) => void }) => {
  const { t } = useTranslation()
  return (
    <div className="mb-6 flex w-1/3 items-center gap-2">
      <StatusStep
        isActive={currentStep === EditStep.EditCredentials}
        text={t('modal.steps.verify', { ns: 'pluginTrigger' })}
        onClick={() => onStepClick?.(EditStep.EditCredentials)}
        clickable={currentStep === EditStep.EditConfiguration}
      />
      <div className="h-px w-3 shrink-0 bg-divider-deep"></div>
      <StatusStep
        isActive={currentStep === EditStep.EditConfiguration}
        text={t('modal.steps.configuration', { ns: 'pluginTrigger' })}
      />
    </div>
  )
}

export const ApiKeyEditModal = ({ onClose, subscription, pluginDetail }: Props) => {
  const { t } = useTranslation()
  const detail = usePluginStore(state => state.detail)
  const { refetch } = useSubscriptionList()

  const [currentStep, setCurrentStep] = useState<EditStep>(EditStep.EditCredentials)
  const [verifiedCredentials, setVerifiedCredentials] = useState<Record<string, unknown> | null>(null)

  const { mutate: updateSubscription, isPending: isUpdating } = useUpdateTriggerSubscription()
  const { mutate: verifyCredentials, isPending: isVerifying } = useVerifyTriggerSubscription()

  const parametersSchema = useMemo<ParametersSchema[]>(
    () => detail?.declaration?.trigger?.subscription_constructor?.parameters || [],
    [detail?.declaration?.trigger?.subscription_constructor?.parameters],
  )

  const apiKeyCredentialsSchema = useMemo(() => {
    const rawSchema = detail?.declaration?.trigger?.subscription_constructor?.credentials_schema || []
    return rawSchema.map(schema => ({
      ...schema,
      tooltip: schema.help,
    }))
  }, [detail?.declaration?.trigger?.subscription_constructor?.credentials_schema])

  const basicFormRef = useRef<FormRefObject>(null)
  const parametersFormRef = useRef<FormRefObject>(null)
  const credentialsFormRef = useRef<FormRefObject>(null)

  const handleVerifyCredentials = () => {
    const credentialsFormValues = credentialsFormRef.current?.getFormValues({
      needTransformWhenSecretFieldIsPristine: true,
    }) || { values: {}, isCheckValidated: false }

    if (!credentialsFormValues.isCheckValidated)
      return

    const credentials = credentialsFormValues.values

    verifyCredentials(
      {
        provider: subscription.provider,
        subscriptionId: subscription.id,
        credentials,
      },
      {
        onSuccess: () => {
          toast.success(t('modal.apiKey.verify.success', { ns: 'pluginTrigger' }))
          // Only save credentials if any field was modified (not all hidden)
          setVerifiedCredentials(areAllCredentialsHidden(credentials) ? null : credentials)
          setCurrentStep(EditStep.EditConfiguration)
        },
        onError: async (error: unknown) => {
          const errorMessage = await parsePluginErrorMessage(error) || t('modal.apiKey.verify.error', { ns: 'pluginTrigger' })
          toast.error(errorMessage)
        },
      },
    )
  }

  const handleUpdate = () => {
    const basicFormValues = basicFormRef.current?.getFormValues({})
    if (!basicFormValues?.isCheckValidated)
      return

    const name = basicFormValues.values.subscription_name as string

    let parameters: Record<string, unknown> | undefined

    if (parametersSchema.length > 0) {
      const paramsFormValues = parametersFormRef.current?.getFormValues({
        needTransformWhenSecretFieldIsPristine: true,
      })
      if (!paramsFormValues?.isCheckValidated)
        return

      // Only send parameters if changed
      const hasChanged = !isEqual(paramsFormValues.values, subscription.parameters || {})
      parameters = hasChanged ? paramsFormValues.values : undefined
    }

    updateSubscription(
      {
        subscriptionId: subscription.id,
        name,
        parameters,
        credentials: verifiedCredentials || undefined,
      },
      {
        onSuccess: () => {
          toast.success(t('subscription.list.item.actions.edit.success', { ns: 'pluginTrigger' }))
          refetch?.()
          onClose()
        },
        onError: async (error: unknown) => {
          const errorMessage = await parsePluginErrorMessage(error) || t('subscription.list.item.actions.edit.error', { ns: 'pluginTrigger' })
          toast.error(errorMessage)
        },
      },
    )
  }

  const handleConfirm = () => {
    if (currentStep === EditStep.EditCredentials)
      handleVerifyCredentials()
    else
      handleUpdate()
  }

  const basicFormSchemas: FormSchema[] = useMemo(() => [
    {
      name: 'subscription_name',
      label: t('modal.form.subscriptionName.label', { ns: 'pluginTrigger' }),
      placeholder: t('modal.form.subscriptionName.placeholder', { ns: 'pluginTrigger' }),
      type: FormTypeEnum.textInput,
      required: true,
      default: subscription.name,
    },
    {
      name: 'callback_url',
      label: t('modal.form.callbackUrl.label', { ns: 'pluginTrigger' }),
      placeholder: t('modal.form.callbackUrl.placeholder', { ns: 'pluginTrigger' }),
      type: FormTypeEnum.textInput,
      required: false,
      default: subscription.endpoint || '',
      disabled: true,
      tooltip: t('modal.form.callbackUrl.tooltip', { ns: 'pluginTrigger' }),
      showCopy: true,
    },
  ], [t, subscription.name, subscription.endpoint])

  const credentialsFormSchemas: FormSchema[] = useMemo(() => {
    return apiKeyCredentialsSchema.map(schema => ({
      ...schema,
      type: normalizeFormType(schema.type as string),
      tooltip: schema.help,
      default: subscription.credentials?.[schema.name] || schema.default,
    }))
  }, [apiKeyCredentialsSchema, subscription.credentials])

  const parametersFormSchemas: FormSchema[] = useMemo(() => {
    return parametersSchema.map((schema: ParametersSchema) => {
      const normalizedType = normalizeFormType(schema.type as string)
      return {
        ...schema,
        type: normalizedType,
        tooltip: schema.description,
        default: subscription.parameters?.[schema.name] || schema.default,
        dynamicSelectParams: normalizedType === FormTypeEnum.dynamicSelect
          ? {
              plugin_id: detail?.plugin_id || '',
              provider: detail?.provider || '',
              action: 'provider',
              parameter: schema.name,
              credential_id: subscription.id,
              credentials: verifiedCredentials || undefined,
            }
          : undefined,
        fieldClassName: schema.type === FormTypeEnum.boolean ? 'flex items-center justify-between' : undefined,
        labelClassName: schema.type === FormTypeEnum.boolean ? 'mb-0' : undefined,
      }
    })
  }, [parametersSchema, subscription.parameters, subscription.id, detail?.plugin_id, detail?.provider, verifiedCredentials])

  const confirmButtonText = (() => {
    if (currentStep === EditStep.EditCredentials)
      return isVerifying ? t('modal.common.verifying', { ns: 'pluginTrigger' }) : t('modal.common.verify', { ns: 'pluginTrigger' })

    return isUpdating ? t('operation.saving', { ns: 'common' }) : t('operation.save', { ns: 'common' })
  })()

  const handleBack = () => {
    setCurrentStep(EditStep.EditCredentials)
    setVerifiedCredentials(null)
  }

  const isDisabled = isUpdating || isVerifying
  const title = t('subscription.list.item.actions.edit.title', { ns: 'pluginTrigger' })

  return (
    <Dialog
      open
      disablePointerDismissal
      onOpenChange={(open) => {
        if (!open)
          onClose()
      }}
    >
      <DialogContent
        backdropProps={{ forceRender: true }}
        className="p-0"
      >
        <div data-testid="modal" data-title={title} data-disabled={isDisabled} className="flex max-h-[80dvh] flex-col">
          <div className="relative shrink-0 p-6 pr-14 pb-3">
            <DialogTitle data-testid="modal-title" className="title-2xl-semi-bold text-text-primary">
              {title}
            </DialogTitle>
            <DialogCloseButton className="top-5 right-5 size-8 rounded-lg" />
          </div>
          <div data-testid="modal-content" className="min-h-0 flex-1 overflow-y-auto px-6 py-3">
            {pluginDetail && (
              <ReadmeEntrance pluginDetail={pluginDetail} presentation="dialog" />
            )}

            <MultiSteps currentStep={currentStep} onStepClick={handleBack} />

            {currentStep === EditStep.EditCredentials
              ? (
                  <div className="mb-4">
                    {credentialsFormSchemas.length > 0 && (
                      <BaseForm
                        formSchemas={credentialsFormSchemas}
                        ref={credentialsFormRef}
                        labelClassName="system-sm-medium mb-2 flex items-center gap-1 text-text-primary"
                        formClassName="space-y-4"
                        preventDefaultSubmit={true}
                      />
                    )}
                  </div>
                )
              : (
                  <div className="max-h-[70vh]">
                    <BaseForm
                      formSchemas={basicFormSchemas}
                      ref={basicFormRef}
                      labelClassName="system-sm-medium mb-2 flex items-center gap-1 text-text-primary"
                      formClassName="space-y-4 mb-4"
                    />

                    {parametersFormSchemas.length > 0 && (
                      <BaseForm
                        formSchemas={parametersFormSchemas}
                        ref={parametersFormRef}
                        labelClassName="system-sm-medium mb-2 flex items-center gap-1 text-text-primary"
                        formClassName="space-y-4"
                      />
                    )}
                  </div>
                )}
          </div>
          <div className="flex shrink-0 justify-between p-6 pt-5">
            <div />
            <div className="flex items-center">
              {currentStep === EditStep.EditConfiguration && (
                <>
                  <Button
                    variant="secondary"
                    onClick={handleBack}
                    disabled={isDisabled}
                  >
                    {t('modal.common.back', { ns: 'pluginTrigger' })}
                  </Button>
                  <div className="mx-3 h-4 w-px bg-divider-regular"></div>
                </>
              )}
              <Button
                onClick={onClose}
                disabled={isDisabled}
              >
                {t('operation.cancel', { ns: 'common' })}
              </Button>
              <Button
                className="ml-2"
                variant="primary"
                onClick={handleConfirm}
                disabled={isDisabled}
              >
                {confirmButtonText}
              </Button>
            </div>
          </div>
          {currentStep === EditStep.EditCredentials && (
            <div data-testid="modal-bottom-slot" className="shrink-0">
              <EncryptedBottom />
            </div>
          )}
        </div>
      </DialogContent>
    </Dialog>
  )
}
