import { ActionIcon, Box, Flex, Group, HoverCard, Modal, Typography, notifier } from '@tidbcloud/uikit'
import { Form, FormCheckboxGroup, FormSelect, FormSwitch, FormTextInput, FormCheckbox } from '@tidbcloud/uikit/biz'
import { IconInfoCircle } from '@tidbcloud/uikit/icons'
import { first, isNumber } from 'lodash-es'
import { observer } from 'mobx-react'
import React, { useEffect } from 'react'
import { useForm, useFormContext } from 'react-hook-form'

import {
  useCreateAutoEndpoints,
  useGetDbsByCluster,
  useGetTablesByDb,
  useListAppCluster,
  useGetVectorFieldList
} from 'dbaas/services/dataservice'
import useStores from 'dbaas/stores/useStores'

import BatchOperTips from '../common/BatchOperTips'
import { methodColor, useCreateEndpCallbackHandler } from '../helpers'
import { EndPoint } from '../types'

interface CheckboxLabelProps {
  method: EndPoint['method']
  name: string
  toolTip?: React.ReactNode
}

const CheckboxLabel: React.FC<React.PropsWithChildren<CheckboxLabelProps>> = ({
  method,
  name,
  toolTip
}: CheckboxLabelProps) => {
  return (
    <Group gap={8}>
      <Typography variant="label-lg" c={methodColor(method)}>
        {method.toUpperCase()}
      </Typography>
      <Typography variant="label-lg">{name}</Typography>
      {toolTip && (
        <HoverCard width={320} withArrow position="top" shadow="md">
          <HoverCard.Target>
            <IconInfoCircle />
          </HoverCard.Target>
          <HoverCard.Dropdown>{toolTip}</HoverCard.Dropdown>
        </HoverCard>
      )}
    </Group>
  )
}

interface AgeFormValues {
  cluster: string
  dataBase: string
  table: string
  operations: string[]
  region: string
  timeout: number
  tag: string
  isDeploy: boolean
  vectorFields: string
  vectorFuncs: string
  isVectorEnabled: boolean
  isVectorSearchEnabled: boolean
}

const AgeFormContent = ({ appId }: { appId: string }) => {
  const {
    store: { tenantData, activeProject }
  } = useStores()

  const { watch, setValue, trigger } = useFormContext<AgeFormValues>()

  const cluster = watch('cluster')

  const dataBase = watch('dataBase')

  const table = watch('table')

  const isVectorEnabled = watch('isVectorEnabled')

  const { data: clustList } = useListAppCluster(tenantData.id, activeProject.id, appId, {
    query: {
      enabled: !!appId,
      refetchOnWindowFocus: false
    }
  })

  const { data: dbList } = useGetDbsByCluster(
    tenantData.id,
    activeProject.id,
    appId,
    cluster + '',
    { show_system_db: 'false' },
    {
      query: {
        enabled: !!appId && !!cluster,
        refetchOnWindowFocus: false
      }
    }
  )

  const { data: tableList } = useGetTablesByDb(tenantData.id, activeProject.id, appId, `${cluster}`, dataBase, {
    query: {
      enabled: !!appId && !!cluster && !!dataBase,
      refetchOnWindowFocus: false
    }
  })

  const { data: vectorFieldList } = useGetVectorFieldList(
    tenantData.id,
    activeProject.id,
    appId,
    `${cluster}`,
    dataBase,
    table,
    {
      query: {
        enabled: !!appId && !!table,
        refetchOnWindowFocus: false
      }
    }
  )

  useEffect(() => {
    if (!vectorFieldList?.data?.length || !isVectorEnabled) {
      setValue('isVectorSearchEnabled', false)
      setValue('vectorFields', '')
      setValue('vectorFuncs', '')
      return
    }

    setValue('isVectorSearchEnabled', true)
    setValue('vectorFields', first(vectorFieldList.data) ?? '')
    setValue('vectorFuncs', 'VEC_L2_DISTANCE')
  }, [vectorFieldList, isVectorEnabled])

  return (
    <Box>
      <Typography variant="label-sm" mb={24} c="carbon.7">
        Automatically generate basic https endpoints by simply making a few selections.
      </Typography>
      <Typography variant="title-md">Target</Typography>
      <Typography variant="body-sm" c="carbon.7">
        Create endpoints for your database tables instantly! Just make a few selections, add configurations, and hit the
        generate button.
      </Typography>
      <Group gap="xs" mt={8}>
        <FormSelect
          name="cluster"
          label="Cluster"
          w={240}
          placeholder="Select cluster"
          rules={{ required: 'required' }}
          nothingFoundMessage="No data"
          onChange={(v) => {
            setValue('region', clustList?.data?.find((cluster) => cluster.cluster_id === v)?.region ?? '')
          }}
          data={clustList?.data?.map((v) => ({ label: v.cluster_name || '', value: v.cluster_id || '' })) ?? []}
        ></FormSelect>
        <FormTextInput name="region" display="none" />
        <FormSelect
          name="dataBase"
          label="Database"
          w={240}
          placeholder="Select Database"
          rules={{ required: 'required' }}
          nothingFoundMessage="No data"
          data={dbList?.data ?? []}
        ></FormSelect>
        <FormSelect
          name="table"
          label="Table"
          w={240}
          placeholder="Select Table"
          rules={{ required: 'required' }}
          nothingFoundMessage="No data"
          data={tableList?.data ?? []}
        ></FormSelect>
      </Group>
      <Typography mt={32} variant="title-md">
        Operations
      </Typography>
      <Typography variant="body-sm" c="carbon.7">
        Select from a range of available request methods to generate endpoints. Additionally, opt for Batch operations,
        enabling orchestration of multiple requests in a single API call.
      </Typography>
      <FormCheckboxGroup
        name="operations"
        styles={{
          root: {
            marginTop: 16,
            '> div': {
              display: 'flex',
              flexWrap: 'wrap'
            }
          }
        }}
        data={[
          { label: <CheckboxLabel method="GET" name="(Retrieve)" />, value: 'GET', sx: { width: 150 } },
          { label: <CheckboxLabel method="POST" name="(Create)" />, value: 'POST', sx: { width: 220 } },
          { label: <CheckboxLabel method="PUT" name="(Update)" />, value: 'PUT', sx: { width: 170 } },
          { label: <CheckboxLabel method="DEL" name="(Delete)" />, value: 'DELETE', sx: { width: 170 } },
          {
            label: <CheckboxLabel method="POST" name="(Batch Create)" toolTip={<BatchOperTips />} />,
            value: 'B-POST',
            sx: { width: 200, marginLeft: 150, marginTop: 16 }
          },
          {
            label: <CheckboxLabel method="PUT" name="(Batch Update)" toolTip={<BatchOperTips />} />,
            value: 'B-PUT',
            sx: { width: 200, marginTop: 16, marginLeft: 20 }
          }
        ]}
        // direction="column"
      />

      <Box
        mt={32}
        p={16}
        sx={(t) => ({
          border: `1px solid ${t.colors.carbon[5]}`,
          borderRadius: t.defaultRadius
        })}
      >
        <Flex justify="space-between" align="center">
          <Box>
            <Typography variant="title-md">Vector Search Operations</Typography>
            <Typography variant="body-sm" c="carbon.7" mb={8}>
              Enable vector search operations to perform advanced similarity searches.
            </Typography>
          </Box>
          <FormSwitch name="isVectorEnabled" onLabel="Enabled" offLabel="Disabled" size="lg"></FormSwitch>
        </Flex>
        {!!isVectorEnabled && (
          <Flex align="center" gap={8} mt={16} justify="space-between">
            <FormCheckbox
              name="isVectorSearchEnabled"
              disabled={!table || !vectorFieldList?.data?.length}
              label={
                <Flex align="center">
                  <CheckboxLabel method="POST" name="(Vector Similarity Search)" />
                  <HoverCard position="top" withArrow width={400} shadow="md">
                    <HoverCard.Target>
                      <ActionIcon size="xs" ml={4}>
                        <IconInfoCircle size={14} />
                      </ActionIcon>
                    </HoverCard.Target>
                    <HoverCard.Dropdown>
                      <Typography variant="body-lg">
                        Automatically generates an API to calculate vector distances based on the selected distance
                        function.
                      </Typography>
                    </HoverCard.Dropdown>
                  </HoverCard>
                </Flex>
              }
            />

            <FormSelect
              name="vectorFields"
              placeholder="Vector Field"
              rules={{ required: 'required' }}
              nothingFoundMessage="No data"
              disabled={!table || !vectorFieldList?.data?.length}
              data={vectorFieldList?.data ?? []}
              sx={{ flex: 2 }}
            ></FormSelect>

            <FormSelect
              name="vectorFuncs"
              placeholder="Vector Distance Functions"
              rules={{ required: 'required' }}
              disabled={!table || !vectorFieldList?.data?.length}
              defaultValue="VEC_L2_DISTANCE"
              data={[
                { label: 'VEC_L2_DISTANCE', value: 'VEC_L2_DISTANCE' },
                { label: 'VEC_COSINE_DISTANCE', value: 'VEC_COSINE_DISTANCE' },
                { label: 'VEC_NEGATIVE_INNER_PRODUCT', value: 'VEC_NEGATIVE_INNER_PRODUCT' },
                { label: 'VEC_L1_DISTANCE', value: 'VEC_L1_DISTANCE' }
              ]}
              sx={{ flex: 2 }}
            ></FormSelect>
          </Flex>
        )}
        {!!isVectorEnabled && (!table || !vectorFieldList?.data?.length) && (
          <>
            {!table && (
              <Typography variant="body-sm" c="carbon.7" mt={4}>
                You cannot check POST (Vector Similarity Search) operation because you have not selected table yet.
              </Typography>
            )}
            {!!table && !vectorFieldList?.data?.length && (
              <Typography variant="body-sm" c="carbon.7" mt={4}>
                You cannot check POST (Vector Similarity Search) operation because there is no vector type field in the
                table.
              </Typography>
            )}
          </>
        )}
      </Box>

      <Typography mt={32} variant="title-md">
        Configurations
      </Typography>
      <Typography variant="body-sm" c="carbon.7" mb={8}>
        Timeout and Tag configurations will be applied to all the generated endpoints.
      </Typography>
      <Group align="top">
        <FormTextInput
          name="timeout"
          autoComplete="off"
          sx={{ width: 360 }}
          rules={{
            required: 'required',
            validate: (val) =>
              isNumber(+val) && val >= 1 && val <= 60000 ? undefined : 'Timeout can range from 1 to 60,000'
          }}
          label={
            <Group gap={0}>
              <Typography variant="body-lg">Timeout</Typography>
              <Typography variant="body-lg" c="carbon.6" mr={4}>
                (ms)
              </Typography>
              <HoverCard position="top" withArrow shadow="md">
                <HoverCard.Target>
                  <ActionIcon size="xs">
                    <IconInfoCircle size={14} />
                  </ActionIcon>
                </HoverCard.Target>
                <HoverCard.Dropdown>
                  <Typography variant="body-lg">Range of timeout: 1-60000</Typography>
                </HoverCard.Dropdown>
              </HoverCard>
            </Group>
          }
          onChange={(_e) => {
            trigger('timeout')
          }}
        />
        <FormTextInput
          name="tag"
          sx={{ width: 360 }}
          maxLength={50}
          label={
            <Group gap={0}>
              <Typography variant="body-lg">Tag</Typography>
              <Typography variant="body-lg" c="carbon.6" mr={8}>
                (optional)
              </Typography>
              <HoverCard position="top" withArrow width={400} shadow="md">
                <HoverCard.Target>
                  <ActionIcon size="xs">
                    <IconInfoCircle size={14} />
                  </ActionIcon>
                </HoverCard.Target>
                <HoverCard.Dropdown>
                  <Typography variant="body-lg">
                    Tags are used to group endpoints. If no tag is specified, they will be grouped under a default tag.
                  </Typography>
                </HoverCard.Dropdown>
              </HoverCard>
            </Group>
          }
        />
      </Group>
      <Flex justify="space-between" align="center" mt={32}>
        <Box>
          <Typography variant="title-md">Auto-Deploy Endpoint</Typography>
          <Typography variant="body-sm" c="carbon.7" mb={8}>
            Enabling the 'Auto-Deploy Endpoint' feature will skip manual review and automatically deploy the generated
            <Typography variant="body-sm" c="carbon.7">
              endpoints to your environment with a commit in your configured GitHub repository.
            </Typography>
          </Typography>
        </Box>
        <FormSwitch name="isDeploy" onLabel="On" offLabel="Off" size="lg"></FormSwitch>
      </Flex>
    </Box>
  )
}

export const AgeFormModal = observer(
  ({
    opened,
    appId,
    editEndpoint,
    onClose
  }: {
    opened: boolean
    appId: string
    editEndpoint?: EndPoint | null
    onClose: () => void
  }) => {
    const {
      store: { tenantData, activeProject }
    } = useStores()
    const { updateSelectData } = useCreateEndpCallbackHandler()

    const mutation = useCreateAutoEndpoints()

    const form = useForm<AgeFormValues>({
      defaultValues: {
        cluster: '',
        dataBase: '',
        table: '',
        operations: ['GET', 'POST', 'PUT', 'DELETE'],
        region: '',
        timeout: 30000,
        tag: 'Default',
        isDeploy: false
      }
    })

    const { watch } = form
    const cluster = watch('cluster')
    const dataBase = watch('dataBase')
    const table = watch('table')
    const operations = watch('operations')
    const timeout = watch('timeout')
    const isVectorSearchEnabled = watch('isVectorSearchEnabled')
    const vectorFileds = watch('vectorFields')
    const vectorFuncs = watch('vectorFuncs')

    const submitDisabled = !(
      cluster &&
      dataBase &&
      table &&
      (operations.length > 0 || (isVectorSearchEnabled && vectorFileds && vectorFuncs)) &&
      timeout
    )
    const handleAgetSubmit = async (formValues: AgeFormValues) => {
      const res = await mutation.mutateAsync({
        orgId: tenantData.id,
        projectId: activeProject.id,
        appId,
        data: {
          cluster_id: formValues.cluster,
          configuration: {
            is_deploy: formValues.isDeploy,
            tag: formValues.tag,
            timeout: +formValues.timeout
          },
          db: formValues.dataBase,
          operations: formValues.operations,
          region: formValues.region,
          table: formValues.table,
          vector_search_operations: {
            distance_func: formValues.vectorFuncs,
            field: formValues.vectorFields,
            is_enabled: formValues.isVectorSearchEnabled
          }
        }
      })
      if (res.code !== 200) {
        notifier.error(res.message)
      } else {
        const endp = editEndpoint
          ? editEndpoint
          : ({
              ...first(res.data),
              is_online: formValues.isDeploy ? 1 : 0
            } as EndPoint)
        updateSelectData(endp, true)
        onClose()
      }
    }

    useEffect(() => {
      if (!opened) {
        form.reset()
      }
    }, [opened])

    return (
      <Modal title="Autogenerate Endpoint" size={900} opened={opened} onClose={onClose} closeOnClickOutside={false}>
        <Form
          form={form}
          onSubmit={handleAgetSubmit}
          onCancel={onClose}
          formMode="onChange"
          actionsProps={{ confirmText: 'Generate', disabled: submitDisabled }}
        >
          <AgeFormContent appId={appId} />
        </Form>
      </Modal>
    )
  }
)
