import {
  Alert,
  Button,
  Group,
  LoadingOverlay,
  notifier,
  Select,
  Skeleton,
  Stack,
  Text,
  Typography
} from '@tidbcloud/uikit'
import { IconAlertCircle } from '@tidbcloud/uikit/icons'
import { observer } from 'mobx-react'
import { useMemo } from 'react'
import { Controller, useForm } from 'react-hook-form'
import { useQuery } from 'react-query'

import { renderDescriptiveSelectOption } from 'dbaas/screens/Changefeed/CreateOrEditChangefeed/renderDescriptiveSelectOption'
import { SharedTiDB } from 'dbaas/screens/NextGen/shared/model/shared-tidb-state'
import { ngCalChangefeedFee, useListChangefeedSpecsX, useNgScaleChangefeed } from 'dbaas/services/dataflow'
import {
  ChangefeedServiceCalChangefeedFeeBody,
  ChangefeedServiceScaleChangefeedBody,
  ConsoleapiChangefeed
} from 'dbaas/services/dataflow/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'

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

export const ChangefeedScaleNg = observer(
  ({
    changefeed,
    cluster,
    onCancel,
    onConfirm
  }: {
    changefeed: ConsoleapiChangefeed
    cluster: SharedTiDB
    onCancel: () => void
    onConfirm: () => void
  }) => {
    const { control, handleSubmit, formState, setValue, watch } = useForm<ChangefeedServiceScaleChangefeedBody>({
      defaultValues: {
        changefeed_spec: changefeed.changefeed_spec
      }
    })

    const selectedSpec = watch('changefeed_spec')

    const { data: specs, isLoading: isSpecLoading } = useListChangefeedSpecsX(
      cluster.tidbId!,
      {
        changefeed_type: changefeed.changefeed_type
      },
      {
        query: {
          enabled: Boolean(cluster.tidbId),
          refetchOnWindowFocus: false,
          retry: false,
          onSuccess(response) {
            if (!response?.items?.length) {
              return
            }

            if (!changefeed.changefeed_spec) {
              const fallback = response.items.find((item) => item.name)
              if (fallback?.name) {
                setValue('changefeed_spec', fallback.name)
              }
              return
            }

            const alternative = response.items.find((item) => item.name && item.name !== changefeed.changefeed_spec)
            if (alternative?.name) {
              setValue('changefeed_spec', alternative.name)
            }
          }
        }
      }
    )

    const options = useMemo(() => {
      return (
        specs?.items
          ?.filter((item) => item.name)
          .map((item) => ({
            label: `${item.rcu_num}`,
            description: `The maximum replication performance is ${item.rps_limit} rows/s`,
            value: item.name!,
            disabled: item.name === changefeed.changefeed_spec
          })) ?? []
      )
    }, [specs?.items, changefeed.changefeed_spec])

    const currentOption = options.find((option) => option.value === changefeed.changefeed_spec)
    const scaleChangefeed = useNgScaleChangefeed()
    const buildFeePayload = (spec?: string): ChangefeedServiceCalChangefeedFeeBody => ({
      changefeed_spec: spec,
      duration: '60'
    })
    const {
      data: currentFeeData,
      isFetching: isCurrentFeeFetching,
      error: currentFeeError
    } = useQuery(
      ['ngCalChangefeedFee', cluster.tidbId, changefeed.changefeed_spec],
      () => ngCalChangefeedFee(cluster.tidbId!, buildFeePayload(changefeed.changefeed_spec)),
      {
        enabled: !!cluster.tidbId && !!changefeed.changefeed_spec,
        refetchOnWindowFocus: false,
        retry: false
      }
    )
    const {
      data: feeData,
      isFetching: isNextFeeFetching,
      error: nextFeeError
    } = useQuery(
      ['ngCalChangefeedFee', cluster.tidbId, selectedSpec],
      () => ngCalChangefeedFee(cluster.tidbId!, buildFeePayload(selectedSpec)),
      {
        enabled: !!cluster.tidbId && !!selectedSpec,
        refetchOnWindowFocus: false,
        retry: false
      }
    )
    const isFetchingFee = isCurrentFeeFetching || isNextFeeFetching
    const feeError = currentFeeError || nextFeeError
    const currentFee = currentFeeData?.fee
    const targetFee = feeData?.fee

    const onSubmit = async (payload: ChangefeedServiceScaleChangefeedBody) => {
      await scaleChangefeed.mutateAsync({
        clusterId: cluster.tidbId!,
        changefeedId: changefeed.changefeed_id,
        data: {
          changefeed_spec: payload.changefeed_spec
        }
      })
      notifier.success('Changefeed is scaling...')
      onConfirm()
    }

    return (
      <form onSubmit={handleSubmit(onSubmit)} data-testid="changefeed-scale-form">
        <LoadingOverlay visible={isSpecLoading} overlayProps={{ blur: 2 }} />

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

          <Controller
            name="changefeed_spec"
            control={control}
            rules={{ required: 'Required' }}
            render={({ field }) => (
              <Select
                {...field}
                onChange={(value) => field.onChange(value)}
                error={formState.errors?.changefeed_spec?.message}
                data={options.filter((option) => !option.disabled)}
                label="Change Specification to"
                renderOption={renderDescriptiveSelectOption}
                placeholder="Select the number of changefeed capacity unit"
              />
            )}
          />

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

          <Group justify="space-between">
            <div data-testid="changefeed-scale-cost">
              {isFetchingFee && <Skeleton width={160} height={28} />}
              {!isFetchingFee && !!feeError && <Typography c="red">Failed to calculate fee</Typography>}
              {!isFetchingFee && !feeError && currentFee != null && targetFee != null && currentFee === targetFee && (
                <Fee amount={targetFee} />
              )}
              {!isFetchingFee && !feeError && currentFee != null && targetFee != null && currentFee !== targetFee && (
                <Group gap={8}>
                  <Fee amount={currentFee} deprecated />
                  <Fee amount={targetFee} />
                </Group>
              )}
            </div>

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