import { notifier } from '@tidbcloud/uikit'
import { ActionIcon, Box, Flex, Modal, SegmentedControl, Typography, Loader, Button, Anchor } from '@tidbcloud/uikit'
import { FormSelect, FormSwitch, FormTextInput, Form } from '@tidbcloud/uikit/biz'
import { IconAlertCircle, IconRight } from '@tidbcloud/uikit/icons'
import { observer } from 'mobx-react'
import { useEffect, useState } from 'react'
import { useFormContext } from 'react-hook-form'

import { useAccessCheck } from 'dbaas/contexts/access-control'
import { getSharedCluster, SharedCluster } from 'dbaas/features/ClusterManagement/cluster'
import { filterListProjects, ProjectType } from 'dbaas/features/Project'
import { useListProjects } from 'dbaas/services'
import { useClusterServiceListClusters } from 'dbaas/services/api-clients/v2023/cluster-management/v1beta1'
import { Commonv1beta1ClusterState } from 'dbaas/services/api-clients/v2023/cluster-management/v1beta1/interface'
import { useGetDataApps } from 'dbaas/services/dataservice'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import { useCreateVercelCluster, useGetVercelDatabaseList, useCreateVercelDatabase } from 'dbaas/services/vercel'
import useStores from 'dbaas/stores/useStores'
import useQuery from 'dbaas/utils/useQuery'
import { clusterNameRules, vercelDatabaseNameRules } from 'dbaas/utils/validationRules'

import EnvTips from './EnvTips'
import { ENV_LIST, AppType } from './types.d'

const Step2 = (props: {
  hasTips?: boolean
  onProjectChange?: (value: string) => void
  onTypeChange: (value: string) => void
  onFrameworkChange: (value: string) => void
}) => {
  const { onProjectChange } = props
  const query = useQuery()
  const {
    store: {
      tenantData: { id: orgId },
      orgList
    }
  } = useStores()
  const { getValues, setValue, watch } = useFormContext()
  const projectVal = watch('project')
  const orgVal = watch('organization')
  const cluster = watch('cluster')
  const configurationId = query.get('configurationId')
  const [createModalOpen, setCreateModalOpen] = useState(false)
  const [type, setType] = useState<AppType>('cluster')
  const [frameworkType, setFrameworkType] = useState(ENV_LIST[0].value)
  const [projectList, setProjectList] = useState<{ label: string; value: string }[]>([])
  const [clusterList, setClusterList] = useState<SharedCluster[]>([])
  const [createDatabaseModalOpen, setCreateDatabaseModalOpen] = useState(false)

  const clusterCreationEnabled = useAccessCheck('TidbxCreateInProject', {
    projectId: projectVal
  })

  useEffect(() => {
    onProjectChange?.(projectVal)
  }, [onProjectChange, projectVal])

  const { refetch: fetchClustersList } = useClusterServiceListClusters(
    {
      orgId: orgVal,
      projectId: projectVal,
      skip: 0,
      pageSize: 100
    },
    {
      query: {
        enabled: !!orgVal && !!projectVal,
        refetchInterval: 5 * 1000,
        refetchOnWindowFocus: false,
        onSuccess: (clusters) => {
          const items = (clusters.clusters || [])
            .map((item) => getSharedCluster(item))
            .filter((item) => item?.computed.isServerless)
            .filter((item) => item !== null)
          const availableCluster = items.find((item) => item?.state === Commonv1beta1ClusterState.ACTIVE)
          if (!cluster && availableCluster) {
            setValue('cluster', availableCluster.id)
          }
          setClusterList(items)
        }
      }
    }
  )

  useEffect(() => {
    setValue('organization', `${orgId}`)
  }, [orgId])

  useEffect(() => {
    setValue('project', '')
  }, [orgVal])

  useListProjects(
    orgVal,
    {
      types: [ProjectType.DEDICATED, ProjectType.TIDBX]
    },
    {
      query: {
        enabled: !!orgVal,
        refetchInterval: false,
        refetchOnWindowFocus: false,
        onSuccess: async (res) => {
          const list = filterListProjects(res.items)
          const val = (list.length && list[0].id) || ''
          setValue('project', val)

          setProjectList(
            list.map(({ id, name }) => ({
              label: name,
              value: id
            }))
          )
        },
        onError: (err) => {
          notifier.error(getErrorMessage(err))
        }
      }
    }
  )

  useEffect(() => {
    setClusterList([])
    setValue('cluster', '')
    setValue('dataapp', '')
    setValue('database', '')
  }, [projectVal])

  useEffect(() => {
    setValue('database', '')
  }, [cluster])

  const { data: databaseList, refetch: fetchDatabaseList } = useGetVercelDatabaseList(
    orgVal,
    getValues('project') || '',
    cluster,
    {
      query: {
        enabled: !!orgId && !!projectVal && !!cluster,
        refetchOnWindowFocus: false,
        refetchOnReconnect: false,
        refetchOnMount: false,
        onSuccess: (data) => {
          if (data.databases?.length) {
            setValue('database', `${data.databases[0]}`)
          }
        }
      }
    }
  )

  const { data: dataapps } = useGetDataApps(orgVal, getValues('project') || '', undefined, {
    query: {
      enabled: !!(!!orgId && !!projectVal),
      refetchInterval: false,
      refetchOnWindowFocus: false,
      onSuccess: (data) => {
        if (data?.data?.length) {
          setValue('dataapp', `${data.data[0].id}`)
        }
      },
      onError: (err) => {
        notifier.error(getErrorMessage(err))
      }
    }
  })

  const createMutation = useCreateVercelCluster({
    request: {
      timeout: 60 * 1000
    }
  })

  const createDatabaseMutation = useCreateVercelDatabase()

  const createCluster = (values: { clusterName: string }) => {
    createMutation
      .mutateAsync({
        orgId: getValues('organization') || '',
        projectId: getValues('project') || '',
        data: {
          cluster_name: values.clusterName,
          configuration_id: configurationId || '',
          selected_vercel_projects: (getValues('vercelProjects') || []).map(
            (item: string) => item && JSON.parse(item).id
          )
        }
      })
      .then(() => {
        fetchClustersList()
      })
  }

  const createDatabase = (values: { databaseName: string }) => {
    createDatabaseMutation
      .mutateAsync({
        orgId: getValues('organization') || '',
        projectId: getValues('project') || '',
        clusterId: getValues('cluster'),
        data: {
          database_name: values.databaseName
        }
      })
      .then(() => {
        fetchDatabaseList()
      })
  }

  useEffect(() => {
    if (!createModalOpen) {
      createMutation.reset()
    }
  }, [createModalOpen])

  useEffect(() => {
    if (!createDatabaseModalOpen) {
      createDatabaseMutation.reset()
    }
  }, [createDatabaseModalOpen])

  const createModal = (params: {
    type: 'cluster' | 'database'
    title: string
    opened: boolean
    status: {
      isError?: boolean
      isSuccess?: boolean
      isLoading?: boolean
    }
    createDisabled: boolean
    rules?: {
      required?: boolean
      pattern?: {
        value?: any
        message: string
      }
    }
    onClose: () => void
    onSubmit: (values: { [key: string]: string }) => void
  }) => {
    const { type, title, opened, status, createDisabled, onSubmit, onClose } = params
    return (
      <Modal
        size={480}
        centered
        title={title}
        opened={opened}
        trapFocus={false}
        returnFocus={false}
        closeOnEscape={false}
        closeOnClickOutside={false}
        withCloseButton={false}
        onClose={onClose}
      >
        {status.isError && (
          <Flex align="center" direction="column">
            <ActionIcon size={80} radius="xl" color="yellow.5">
              <IconAlertCircle size={50} />
            </ActionIcon>

            <Typography variant="label-lg" mt={16}>
              Creating {type} failed.
            </Typography>
            <Typography variant="label-lg">
              <span dangerouslySetInnerHTML={{ __html: getErrorMessage(createMutation.error) }}></span>
            </Typography>

            <Button variant="default" mt={16} onClick={onClose} data-mp-event="mp-close-1691461012411">
              Close
            </Button>
          </Flex>
        )}

        {status.isSuccess && (
          <Flex align="center" direction="column">
            <ActionIcon size={50} variant="filled" radius="xl" color="green.5">
              <IconRight />
            </ActionIcon>

            <Typography variant="label-lg" c="carbon.7" mt={16}>
              {' '}
              Creating {type} succeed.
            </Typography>
            <Typography variant="label-lg" c="carbon.7">
              You can go back and select at dropdown.
            </Typography>

            <Button variant="default" mt={16} onClick={onClose} data-mp-event="mp-back-1691461012413">
              Back
            </Button>
          </Flex>
        )}

        {status.isLoading && (
          <Flex align="center" direction="column">
            <Loader size="md" />
            <Typography variant="label-lg" c="carbon.7" mt={16}>
              {' '}
              Your {type} is creating.
            </Typography>
            <Typography variant="label-lg" c="carbon.7">
              Please wait for a few seconds.
            </Typography>
          </Flex>
        )}

        {!status.isLoading && !status.isSuccess && !status.isError && (
          <Form onSubmit={onSubmit} layout="none" stopPropagation preventDefault withActions={false}>
            <FormTextInput
              label={`${type === 'cluster' ? 'Cluster' : 'Database'} Name`}
              name={`${type === 'cluster' ? 'cluster' : 'database'}Name`}
              placeholder={`Name your new ${type}`}
              required
              rules={type === 'cluster' ? clusterNameRules : vercelDatabaseNameRules}
              autoComplete="new-name"
            />
            <Flex gap={24} justify="flex-end" mt={96}>
              <Button variant="default" onClick={onClose} data-mp-event="mp-cancel-1691461012417">
                cancel
              </Button>
              <Button
                data-mp-event={`Vercel Create ${type === 'cluster' ? 'Cluster' : 'Database'} Confirm Button Clicked`}
                type={!createDisabled ? 'submit' : void 0}
                disabled={createDisabled}
                loading={status.isLoading}
              >
                Create
              </Button>
            </Flex>
          </Form>
        )}
      </Modal>
    )
  }

  return (
    <Box m="0">
      <FormSelect
        name="organization"
        label="TiDB Cloud Organization"
        placeholder="Select TiDB Cloud organization"
        data={orgList.map(({ id, name }) => ({
          label: name,
          value: id
        }))}
      />

      <FormSelect
        mt={24}
        name="project"
        label="TiDB Cloud Project"
        placeholder="Select TiDB Cloud project"
        data={projectList}
        nothingFoundMessage="No TiDB Cloud project found"
      />

      <Typography mt={24} mb={8} variant="label-lg" c="carbon.9">
        Connection Type
      </Typography>
      <SegmentedControl
        data={[
          { label: 'Cluster', value: 'cluster' },
          { label: 'Data App', value: 'dataapp' }
        ]}
        onChange={(value: AppType) => {
          setType(value)
          props.onTypeChange(value)
        }}
      />

      <Box
        sx={() => ({
          display: type === 'cluster' ? 'block' : 'none'
        })}
      >
        <FormSelect
          mt={24}
          name="cluster"
          label="Cluster"
          placeholder="Select cluster"
          data={clusterList.map((cluster) => ({
            label: cluster.displayName,
            value: `${cluster.id}`,
            disabled: cluster.state !== Commonv1beta1ClusterState.ACTIVE
          }))}
          creatable={clusterCreationEnabled}
          searchable
          getCreateLabel={() => {
            return '+ Create Cluster'
          }}
          onCreate={() => {
            setCreateModalOpen(true)
            if (getValues('cluster')) {
              return {
                value: getValues('cluster'),
                label: getValues('cluster')
              }
            }

            return null
          }}
        />

        <FormSelect
          mt={24}
          name="database"
          label="Database"
          placeholder="Select database"
          disabled={!cluster}
          data={(databaseList?.databases || []).map((item) => ({
            label: item,
            value: item
          }))}
          creatable
          searchable
          getCreateLabel={() => '+ Create Database'}
          onCreate={() => {
            setCreateDatabaseModalOpen(true)
            if (getValues('database_name')) {
              return {
                value: getValues('database_name'),
                label: getValues('database_name')
              }
            }

            return null
          }}
        />

        <FormSelect
          mt={24}
          name="framework_type"
          label="Framework"
          data={ENV_LIST}
          onChange={(value) => {
            props.onFrameworkChange(value || '')
            setFrameworkType(value || '')
          }}
        />

        <Flex align="center" mt={24} justify="space-between">
          <Box>
            <Typography variant="title-md" fw={500}>
              Branching
            </Typography>
            <Typography>Create a branch for the preview environment</Typography>
          </Box>
          <FormSwitch size="md" name="branch_enabled" />
        </Flex>

        {props.hasTips !== false && <EnvTips type={type} env={frameworkType} />}
      </Box>

      <Box
        sx={() => ({
          display: type === 'dataapp' ? 'block' : 'none'
        })}
      >
        <FormSelect
          mt={24}
          name="dataapp"
          label="Data App"
          placeholder="Select Data App"
          required
          rules={{
            required: type === 'dataapp' ? 'Please select a Data App' : ''
          }}
          data={(dataapps?.data || []).map((app) => ({
            label: app.app_name || '',
            value: `${app.id}`
          }))}
          nothingFoundMessage={
            <Box>
              <Typography>No Data App in this project,</Typography>
              please go to
              <Anchor href="/project/data-service" target="_blank" c="peacock.5" m="0 4px">
                create a new Data App
              </Anchor>{' '}
              and refresh here.
            </Box>
          }
        />

        {props.hasTips !== false && <EnvTips type="dataapp" env="" />}
      </Box>

      {createModal({
        type: 'cluster',
        title: 'Create New Cluster',
        opened: createModalOpen,
        onClose: () => setCreateModalOpen(false),
        status: {
          isError: createMutation.isError,
          isSuccess: createMutation.isSuccess,
          isLoading: createMutation.isLoading
        },
        createDisabled: !clusterCreationEnabled,
        onSubmit: createCluster
      })}

      {createModal({
        type: 'database',
        title: 'Create New Database',
        opened: createDatabaseModalOpen,
        onClose: () => setCreateDatabaseModalOpen(false),
        status: {
          isError: createDatabaseMutation.isError,
          isSuccess: createDatabaseMutation.isSuccess,
          isLoading: createDatabaseMutation.isLoading
        },
        createDisabled: !clusterCreationEnabled,
        onSubmit: createDatabase
      })}
    </Box>
  )
}

export default observer(Step2)
