import { zodResolver } from '@hookform/resolvers/zod'
import { notifier } from '@tidbcloud/uikit'
import { observer } from 'mobx-react'
import { useCallback, useId, useState } from 'react'
import { FormProvider, Resolver, useForm } from 'react-hook-form'
import { useHistory, useLocation } from 'react-router-dom'

import { markOneConsoleFeedbackEventCompleted } from 'dbaas/layouts/v5/NewNavGuide/feedbackState'
import { useCreateResourceRoleState } from 'dbaas/screens/NextGen/shared/access/create-resource-role'
import { Serverlessv1beta1ClusterHighAvailabilityType } from 'dbaas/services/api-clients/v2023/serverless/v1beta1/interface'
import useStores from 'dbaas/stores/useStores'

import { TwoPaneLayout } from '../../layout/TwoPaneLayout'
import { useVirtualProjectId } from '../../shared/use-virtual-project-id'
import { EssentialV2Summary } from '../EssentialV2/EssentialV2Summary'
import { createEssentialV2FormSchema } from '../EssentialV2/schema'
import { EssentialV2FormValue } from '../EssentialV2/types'
import { useCreateEssentialV2 } from '../EssentialV2/use-create-essential-v2'

import { getEssentialPlanTransitionValues } from './essential-plan-transition'
import { EssentialServicePlan } from './essential-regions'
import { EssentialForm } from './EssentialForm'
import { EssentialSummary } from './EssentialSummary'
import { ESSENTIAL_RCU_MIN, createEssentialFormSchema } from './schema'
import { AdaptiveEssentialFormValue, EssentialFormValue } from './types'
import { useCreateEssential } from './use-create-essential'

interface EssentialCreationProps {
  header: React.ReactNode
  planSelector: React.ReactNode
  active: boolean
}

export const EssentialCreation = observer(({ header, planSelector, active }: EssentialCreationProps) => {
  const history = useHistory()
  const location = useLocation()
  const {
    store: {
      userProfile: { id: userId },
      lastVisitLocation: { orgId }
    },
    actions: { refreshOrgData }
  } = useStores()

  const virtualProjectId = useVirtualProjectId()
  const { requiresProjectSelection, isOrgOwner } = useCreateResourceRoleState()
  const [servicePlan, setServicePlan] = useState<EssentialServicePlan>()
  const [regionName, setRegionName] = useState('')

  const resolver: Resolver<AdaptiveEssentialFormValue> = useCallback(
    (values, context, options) => {
      const resolvedProjectId = isOrgOwner ? values.projectId || virtualProjectId : values.projectId
      const schema =
        servicePlan === 'Essential_V2'
          ? createEssentialV2FormSchema(orgId, resolvedProjectId, {
              requireProjectSelection: requiresProjectSelection
            })
          : createEssentialFormSchema({ requireProjectSelection: requiresProjectSelection })

      return zodResolver(schema)(values, context, options) as ReturnType<Resolver<AdaptiveEssentialFormValue>>
    },
    [isOrgOwner, orgId, requiresProjectSelection, servicePlan, virtualProjectId]
  )

  const formMethods = useForm<AdaptiveEssentialFormValue>({
    mode: 'onChange',
    defaultValues: {
      projectId: '',
      provider: '',
      region: '',
      name: '',
      encrypted: true,
      minRcu: ESSENTIAL_RCU_MIN,
      maxRcu: 10000,
      highAvailabilityType: Serverlessv1beta1ClusterHighAvailabilityType.REGIONAL
    },
    resolver
  })

  const handleSuccess = useCallback(
    (tidbId: string) => {
      refreshOrgData()
      markOneConsoleFeedbackEventCompleted(userId, 'creation')
      notifier.success('Creating TiDB Cloud Essential Instance...')
      if (tidbId) {
        history.push(`/tidbs/${tidbId}/overview${location.search}`)
      } else {
        history.push(`/tidbs${location.search}`)
      }
    },
    [history, location.search, refreshOrgData, userId]
  )
  const handleError = useCallback((errorMsg: string) => {
    notifier.error(<div dangerouslySetInnerHTML={{ __html: errorMsg }} />)
  }, [])

  const { createTidb: createEssential, isCreating: isCreatingEssential } = useCreateEssential({
    onSuccess: handleSuccess,
    onError: handleError
  })
  const { createTidb: createEssentialV2, isCreating: isCreatingEssentialV2 } = useCreateEssentialV2({
    onSuccess: handleSuccess,
    onError: handleError
  })

  const handleRegionChange = useCallback(
    (nextRegionName: string, nextServicePlan: EssentialServicePlan) => {
      setRegionName(nextRegionName)
      if (servicePlan !== nextServicePlan) {
        const nextValues = getEssentialPlanTransitionValues(
          formMethods.getValues('encrypted'),
          nextServicePlan,
          formMethods.getFieldState('encrypted').isDirty
        )
        formMethods.setValue('encrypted', nextValues.encrypted)
        formMethods.setValue('minRcu', nextValues.minRcu)
        formMethods.setValue('maxRcu', nextValues.maxRcu)
        formMethods.clearErrors(['encrypted', 'minRcu', 'maxRcu', 'highAvailabilityType'])
      }
      setServicePlan(nextServicePlan)
    },
    [formMethods, servicePlan]
  )

  const handleValidSubmit = useCallback(
    async (data: AdaptiveEssentialFormValue) => {
      const resolvedProjectId = isOrgOwner ? data.projectId || virtualProjectId : data.projectId

      if (servicePlan === 'Essential_V2') {
        await createEssentialV2({ ...data, projectId: resolvedProjectId } as EssentialV2FormValue)
        return
      }

      await createEssential({ ...data, projectId: resolvedProjectId } as EssentialFormValue)
    },
    [createEssential, createEssentialV2, isOrgOwner, servicePlan, virtualProjectId]
  )
  const formId = useId()
  const isCreating = servicePlan === 'Essential_V2' ? isCreatingEssentialV2 : isCreatingEssential
  const summary =
    servicePlan === 'Essential_V2' ? (
      <EssentialV2Summary formId={formId} isPending={isCreating} regionName={regionName} />
    ) : servicePlan === 'Essential' ? (
      <EssentialSummary formId={formId} isPending={isCreating} regionName={regionName} />
    ) : null

  return (
    <FormProvider {...formMethods}>
      <TwoPaneLayout visible={active} header={header} rightSection={summary}>
        <EssentialForm
          formId={formId}
          planSelector={planSelector}
          onRegionChange={handleRegionChange}
          onSubmit={formMethods.handleSubmit(handleValidSubmit)}
        />
      </TwoPaneLayout>
    </FormProvider>
  )
})
