import {
  Button,
  Card,
  Divider,
  Group,
  HoverCard,
  Loader,
  Modal,
  ScrollArea,
  SimpleGrid,
  Stack,
  Text,
  Typography,
  UnstyledButton
} from '@tidbcloud/uikit'
import { FormSelect } from '@tidbcloud/uikit/biz'
import { IconInfoCircle } from '@tidbcloud/uikit/icons'
import { useMount } from 'ahooks'
import { capitalize } from 'lodash-es'
import { observer } from 'mobx-react'
import React, { forwardRef, useMemo, useState } from 'react'
import { FormProvider, useForm } from 'react-hook-form'
import { useHistory } from 'react-router-dom'

import { FormErrorMessage } from 'dbaas/components/Form'
import type { FormData } from 'dbaas/screens/DataMigration/CreateDataMigrationDedicated'
import SelectedObjects from 'dbaas/screens/DataMigration/DMJobDetail/SelectedObject'
import { useCreateConnProfile, useCreateDMJob, useGetDMCost, useListDMJobSpecs } from 'dbaas/services/dataflow'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'
import { eventTracking } from 'dbaas/utils/tracking'

import { BillingDetail } from './BillingDetail'

interface ItemProps extends React.ComponentPropsWithoutRef<'div'> {
  value: string
  label: string
  maxFullSpeed?: string
  maxIncrSpeed?: string
}

const SelectItem = forwardRef<HTMLDivElement, ItemProps>(
  ({ value, label, maxFullSpeed, maxIncrSpeed, ...others }: ItemProps, ref) => (
    <div ref={ref} {...others}>
      <Group wrap="nowrap">
        <div>
          <Text size="sm">{label}</Text>
          <Text size="xs" opacity={0.65}>
            {`The maximum full and incremental performances are ${maxFullSpeed} MiB/s and ${maxIncrSpeed} rows/s respectively`}
          </Text>
        </div>
      </Group>
    </div>
  )
)

const Step4 = ({
  onCancel,
  onGoPrev,
  formData
}: {
  formData: FormData
  onCancel: () => void
  onGoPrev: () => void
}) => {
  const {
    store: { tenantData, activeProjectId, currentCluster }
  } = useStores()
  const method = useForm({
    defaultValues: {
      spec: '2' // use 4 rcu as default
    }
  })
  const history = useHistory()
  const [modalOpen, setModalOpen] = useState(false)
  const { handleSubmit, watch } = method
  const specId = watch('spec')
  const { data, isLoading } = useListDMJobSpecs({
    query: {
      refetchOnWindowFocus: false
    }
  })
  const specOptions = useMemo(() => {
    return (
      data?.specs?.map((i) => ({
        label: `${i.capacity_unit} RCUs`,
        value: i.id!,
        maxFullSpeed: i.max_full_phase_speed,
        maxIncrSpeed: i.max_incr_phase_speed
      })) ?? []
    )
  }, [data])

  const jobType = useMemo(() => {
    return [
      {
        text: `Existing data migration`,
        enable: formData.migration_mode?.includes('full')
      },
      {
        text: `Incremental migration`,
        enable: formData.migration_mode?.includes('incremental')
      }
    ]
      .filter((i) => i.enable)
      .map((i) => i.text)
      .join(', ')
  }, [formData.migration_mode])

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

  const totalCost = useMemo(() => {
    if (!costData) return 0
    return ((costData.node_cost ?? 0) + (costData.private_link_cost ?? 0)).toFixed(4).replace(/\.0+$/, '')
  }, [costData])

  const [errorMessage, setErrorMessage] = useState('')
  const createConnProfile = useCreateConnProfile()
  const createDMJob = useCreateDMJob()

  const onSubmit = async (data: { spec: string }) => {
    const isPrivateLink = formData.connect_method?.toLowerCase().includes('private')

    try {
      const res = await createConnProfile.mutateAsync({
        orgId: tenantData.id,
        projectId: activeProjectId,
        clusterId: currentCluster?.id!,
        data: {
          name: formData.name,
          type: formData.data_source,
          conn_method: formData.connect_method,
          endpoint_service_name: isPrivateLink ? formData.service_endpoint || undefined : undefined,
          host: isPrivateLink ? undefined : formData.host,
          port: formData.port,
          user: formData.username,
          password: formData.password,
          ssl_ca: formData.ssl_ca || undefined,
          ssl_cert: formData.ssl_cert || undefined,
          ssl_key: formData.ssl_key || undefined
        }
      })

      await createDMJob.mutateAsync({
        orgId: tenantData.id,
        projectId: activeProjectId,
        clusterId: currentCluster?.id!,
        data: {
          name: formData.name,
          sources: [
            {
              ...formData.sources[0],
              conn_profile_id: res.id
            }
          ],
          cluster_user: formData.cluster_username,
          cluster_password: formData.cluster_password,
          mode: formData.mode,
          spec_id: data.spec,
          full_instance_migrate: formData.full_instance_migrate,
          precheck_id: formData.precheckId,
          import_mode: formData.import_mode!
        }
      })

      eventTracking('Choose a spec and start DataMigration job succeed')

      history.push(`/clusters/${currentCluster?.id}/data-migration`)
    } catch (e) {
      setErrorMessage(getErrorMessage(e))
    }
  }

  useMount(() => {
    eventTracking('Enter the step to choose the spec of DataMigration job')
  })

  if (isLoading) {
    return <Loader size={`xs`} />
  }

  return (
    <FormProvider {...method}>
      <Card withBorder shadow="none" p={0}>
        <form onSubmit={handleSubmit(onSubmit)}>
          <Stack m={24}>
            <Text fw={700} fz={18}>
              Migration Specification
            </Text>

            <Stack>
              <Text>
                TiDB Cloud measures the Data Migration (DM) capacity in Replication Capacity Units (RCUs) billed per
                hour. As the number of RCU increases, the performance of a DM job also increases.
              </Text>
              <Text>The performance values are for reference only and might vary in different scenarios.</Text>
            </Stack>

            <FormSelect
              name="spec"
              data={specOptions}
              renderOption={(item: { option: (typeof specOptions)[number] }) => <SelectItem {...item.option} />}
              label={
                <Group>
                  <Text>Specify the number of RCU used by this DM job</Text>
                  <HoverCard withArrow shadow="md" width={400}>
                    <HoverCard.Target>
                      <IconInfoCircle size={16} />
                    </HoverCard.Target>
                    <HoverCard.Dropdown>
                      <Typography variant="body-lg">
                        DataMigration(DM) specifications and billing details in TiDB Cloud, refer to the{' '}
                        <a
                          href="https://docs.pingcap.com/tidbcloud/tidb-cloud-billing-dm"
                          target="_blank"
                          rel="noreferrer"
                        >
                          document
                        </a>
                        .
                      </Typography>
                    </HoverCard.Dropdown>
                  </HoverCard>
                </Group>
              }
            />
          </Stack>

          <Divider />

          <Stack m={24}>
            <Text fw={700} fz={18}>
              Job Configuration
            </Text>

            <Stack>
              <Group>
                <Text w={200}>Name</Text>
                <Text fw={500}>{formData.name}</Text>
              </Group>
              <Group>
                <Text w={200}>Type</Text>
                <Text fw={500}>{jobType}</Text>
              </Group>
            </Stack>
          </Stack>

          <Divider />

          <Stack m={24}>
            <Text fw={700} fz={18}>
              Source Connection Profile
            </Text>

            <SimpleGrid cols={4}>
              <div>Data source</div>
              <b>{formData.data_source}</b>
              {formData.connect_method?.includes('private') ? (
                <>
                  <div>Endpoint service name</div>
                  <b>{formData.service_endpoint}</b>
                </>
              ) : (
                <>
                  <div>Hostname or IP address</div>
                  <b>{formData.host}</b>
                </>
              )}
              <div>Port</div>
              <b>{formData.port}</b>
              <div>Connectivity method</div>
              <b>{formData.connect_method_display_name}</b>
              <div>Username</div>
              <b>{formData.username}</b>
              <div>SSL/TLS</div>
              <b>{formData.ssl ? 'Enabled' : 'Disabled'}</b>
              <div>Selected Objects</div>
              <b>
                {formData.selectObjectMethod === 'customize' ? (
                  <a onClick={() => setModalOpen(true)}>Show Detail</a>
                ) : (
                  'All'
                )}
              </b>
              <div>Import Mode</div>
              <b>{capitalize(formData.import_mode)}</b>
            </SimpleGrid>
          </Stack>
          <Divider />

          <Stack m={24}>
            <Text fw={700} fz={18}>
              Target Connection Profile
            </Text>

            <SimpleGrid cols={4}>
              <div>Region</div>
              <b>{currentCluster?.regionDisplayName}</b>
              <div>Cluster ID</div>
              <b>{currentCluster?.id}</b>
              <div>Cluster name</div>
              <b>{currentCluster?.displayName}</b>
              <div>User name</div>
              <b>{formData.cluster_username}</b>
            </SimpleGrid>
          </Stack>

          <Divider />

          <FormErrorMessage message={errorMessage} />

          <Group m={24} justify="space-between">
            <HoverCard position="top" offset={16} width={600} shadow="md" withArrow>
              <HoverCard.Target>
                <UnstyledButton>
                  {isFetching ? (
                    <Loader size="xs" />
                  ) : (
                    <Group>
                      <Text fw={700} fz={24}>{`$ ${totalCost}/Hour`}</Text>
                      <IconInfoCircle size={16} />
                    </Group>
                  )}
                </UnstyledButton>
              </HoverCard.Target>
              <HoverCard.Dropdown>
                <div className="wd-flex">
                  <BillingDetail
                    className="wd-flex-1 wd-mr-12"
                    details={
                      [
                        {
                          name: `${specOptions.find((i) => i.value === specId)?.label ?? '-'}`,
                          value: `$ ${costData?.node_cost}`
                        },
                        costData?.private_link_cost
                          ? { name: `PrivateLink VPC Endpoints`, value: `$ ${costData?.private_link_cost}` }
                          : null,
                        { name: 'Total', value: `$ ${totalCost}/Hour`, bold: true },
                        {
                          name: `Monthly Estimate`,
                          value: `$ ${(Number(totalCost) * 24 * 30).toFixed(4).replace(/\.0+$/, '')}/Month`,
                          bold: true
                        }
                      ].filter(Boolean) as any
                    }
                  />

                  <div className="wd-w-3/12 wd-flex wd-flex-col wd-justify-end">
                    <Text fz={14} fw={700}>
                      Data transfer
                    </Text>
                    <Text fz={12}>
                      Data transfers from your source database to TiDB cloud clusters will be billed according to your
                      chosen cloud provider. See{' '}
                      <a
                        href="https://www.pingcap.com/tidb-dedicated-pricing-details/#data-transfer-cost"
                        target="_blank"
                        rel="noopener noreferrer"
                      >
                        Data Transfer Cost
                      </a>{' '}
                      for more information.
                    </Text>
                  </div>
                </div>
              </HoverCard.Dropdown>
            </HoverCard>

            <Group justify="space-between">
              <Group>
                <Button variant="default" type="button" onClick={onCancel} data-mp-event="mp-cancel-1691461016888">
                  Cancel
                </Button>

                <Button variant="outline" type="button" onClick={onGoPrev} data-mp-event="mp-previous-1691461016891">
                  Previous
                </Button>

                <Button
                  type="submit"
                  loading={createConnProfile.isLoading || createDMJob.isLoading}
                  data-mp-event="mp-createjobandstart-1691461016892"
                >
                  Create Job and Start
                </Button>
              </Group>
            </Group>
          </Group>
        </form>

        <Modal
          opened={modalOpen}
          centered
          size="xl"
          title={
            <Text fw={700} fz={20}>
              Selected Migration Objects
            </Text>
          }
          onClose={() => setModalOpen(false)}
        >
          <ScrollArea.Autosize mah={300}>
            <SelectedObjects rules={formData.sources?.[0]?.ba_rules} />
          </ScrollArea.Autosize>
        </Modal>
      </Card>
    </FormProvider>
  )
}

export const DedicatedDMStep4 = observer(Step4)
