import { Alert, Button, Group, Loader, LoadingOverlay, notifier, Stack, Text, Typography } from '@tidbcloud/uikit'
import { FormSelect } from '@tidbcloud/uikit/biz'
import { IconAlertCircle } from '@tidbcloud/uikit/icons'
import { observer } from 'mobx-react'
import { useMemo } from 'react'
import { FormProvider, useForm } from 'react-hook-form'

import { ConnectionMethod } from 'dbaas/features/DataMigration'
import { renderDescriptiveSelectOption } from 'dbaas/screens/Changefeed/CreateOrEditChangefeed/renderDescriptiveSelectOption'
import { useGetDMCost, useListDMJobSpecs, useScaleUpDownJob } from 'dbaas/services/dataflow'
import { DmGetCostResp, DmJob, ScaleUpDownJobBody } from 'dbaas/services/dataflow/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'

function Fee({ n, deprecated }: { n?: number; deprecated?: boolean }) {
  return (
    <Text span fz={20} c={deprecated ? 'carbon.6' : 'carbon.7'} td={deprecated ? 'line-through' : undefined}>
      <Text span fw={700} c={deprecated ? 'carbon.6' : 'carbon.9'}>
        {`$${n?.toFixed(4) ?? 0}`}
      </Text>
      {!deprecated && (
        <Text span fz={14}>
          /hour
        </Text>
      )}
    </Text>
  )
}

const getTotalCost = (c?: DmGetCostResp) => {
  return (c?.node_cost ?? 0) + (c?.private_link_cost ?? 0)
}

const _DMJobScale = ({ job, onCancel, onConfirm }: { job: DmJob; onCancel?: () => void; onConfirm?: () => void }) => {
  const {
    store: { tenantData, activeProjectId, currentCluster }
  } = useStores()
  const methods = useForm<ScaleUpDownJobBody>({
    defaultValues: {
      to_spec_id: job.spec?.id
    }
  })
  const { watch, handleSubmit, setValue } = methods
  const specId = watch('to_spec_id')

  const { data, isLoading } = useListDMJobSpecs({
    query: {
      onSuccess(data) {
        const spec = data.specs?.find((i) => i.id !== job.spec?.id)
        if (spec && spec.id) {
          setValue('to_spec_id', spec.id)
        }
      }
    }
  })

  const options = useMemo(() => {
    return (
      data?.specs?.map((i) => ({
        label: `${i.capacity_unit} RCUs`,
        description: `The maximum replication performance is ${i.max_full_phase_speed} MiB/s and ${i.max_incr_phase_speed} rows/s respectively`,
        value: i.id!,
        disabled: i.id === job.spec?.id
      })) ?? []
    )
  }, [data, job])

  const currentOption = options.find((i) => i.value === job.spec?.id)

  const scaleJob = useScaleUpDownJob()

  const connetionMethod = useMemo(() => {
    const method = Object.values(job.sub_tasks ?? {})?.[0]?.source?.conn_profile?.conn_method || 'direct'
    return ConnectionMethod[method] || ConnectionMethod['Public IP']
  }, [job])

  const { data: currentCostData } = useGetDMCost(
    tenantData.id,
    activeProjectId,
    currentCluster?.id!,
    {
      conn_method: connetionMethod,
      spec_id: job.spec?.id!
    },
    { query: { enabled: !!currentCluster?.id && !!job.spec?.id, refetchOnWindowFocus: false } }
  )

  const { data: costData, isFetching: isLoadingSelectCost } = useGetDMCost(
    tenantData.id,
    activeProjectId,
    currentCluster?.id!,
    {
      conn_method: connetionMethod,
      spec_id: specId
    },
    { query: { enabled: !!currentCluster?.id && !!specId, refetchOnWindowFocus: false } }
  )

  const onSubmit = async (d: ScaleUpDownJobBody) => {
    await scaleJob.mutateAsync({
      orgId: tenantData.id,
      projectId: activeProjectId,
      clusterId: currentCluster?.id!,
      id: job.id!,
      data: {
        to_spec_id: d.to_spec_id
      }
    })
    notifier.success('Data migration job is scaling...')
    onConfirm?.()
  }

  return (
    <FormProvider {...methods}>
      <form onSubmit={handleSubmit(onSubmit)}>
        <LoadingOverlay visible={isLoading} overlayProps={{ blur: 2 }} />

        <Stack>
          <Stack gap={4}>
            <Text color="carbon.8" fz={14} fw={600}>
              Current Specification
            </Text>
            {currentOption && (
              <Text fz={14}>
                <Group wrap="nowrap" gap={4}>
                  <Typography fw={700} c="carbon.8">
                    {currentOption?.label}
                  </Typography>
                  <Typography c="carbon.7">({currentOption?.description})</Typography>
                </Group>
              </Text>
            )}
          </Stack>

          <FormSelect
            name="to_spec_id"
            data={options.filter((i) => !i.disabled)}
            label="Change Specification to"
            renderOption={renderDescriptiveSelectOption}
            rules={{ required: 'Required' }}
          />

          {scaleJob.error && (
            <Alert color="red" icon={<IconAlertCircle size={14} />}>
              {getErrorMessage(scaleJob.error)}
            </Alert>
          )}

          <Group justify="space-between">
            {isLoadingSelectCost ? (
              <Loader size="xs" />
            ) : costData?.node_cost === currentCostData?.node_cost ? (
              <Fee n={getTotalCost(costData)} />
            ) : (
              <Group gap={8}>
                <Fee n={getTotalCost(currentCostData)} deprecated />
                <Fee n={getTotalCost(costData)} />
              </Group>
            )}

            <Group>
              <Button variant="default" onClick={onCancel} data-mp-event="Cancel DM Job Scale Clicked">
                Cancel
              </Button>
              <Button type="submit" loading={scaleJob.isLoading} data-mp-event="Submit DM Job Scale Clicked">
                Submit
              </Button>
            </Group>
          </Group>
        </Stack>
      </form>
    </FormProvider>
  )
}

export const DMJobScale = observer(_DMJobScale)
