import { Box, Button, Flex, ActionIcon, HoverCard, Group, Stack, Typography, type SelectProps } from '@tidbcloud/uikit'
import { FormSelect, FormSelectProps } from '@tidbcloud/uikit/biz'
import {
  IconPlus,
  IconTrash01,
  IconFolder,
  IconBezierCurve02,
  IconCheck,
  IconDProjectFill
} from '@tidbcloud/uikit/icons'
import { useMemo } from 'react'
import { useFormContext, useFieldArray, useWatch } from 'react-hook-form'

import { ProjectType } from 'dbaas/features/Project'
import { ServicePlanTag } from 'dbaas/screens/NextGen/shared/tidb-instance/service-plan/ServicePlanTag'
import { Commonv1beta1ServicePlan } from 'dbaas/services/api-clients/v2025/tidb-management/v1beta2/interface'

import { ScopeType, RoleScopeTypes } from './RolesView'

export interface ScopeRoleItem {
  rbac_role: string
  scope_type: string
  scope_id: string
}

interface SelectData {
  label: string
  value: string
  servicePlan?: Commonv1beta1ServicePlan
  icon?: React.ReactNode
  description?: string
  projectType?: string
}

interface ScopeRoleSelectProps {
  name: string
  roleSelectProps?: Omit<FormSelectProps, 'name' | 'data'> & { data: SelectData[] }
  scopeSelectProps?: Omit<FormSelectProps, 'name' | 'data'> & { data: SelectData[] }
  defaultRole: string
  scopeType: ScopeType
  disabledTips?: React.ReactNode
}

const getProjectTypeIcon = (projectType?: string) => {
  if (projectType === ProjectType.DEDICATED) {
    return <IconDProjectFill size={16} c="carbon.8" />
  }

  return <IconFolder size={16} c="carbon.8" strokeWidth={1} />
}

const renderInstanceOption: SelectProps['renderOption'] = ({ option, checked }) => {
  const opt = option as SelectData

  return (
    <Group wrap="nowrap" justify="space-between" sx={{ flex: 1 }} h={36}>
      <Group gap={8}>
        {opt.servicePlan && <ServicePlanTag servicePlan={opt.servicePlan} fw={500} px={8} />}
        <Typography variant="title-md" fw={checked ? 500 : 400}>
          {opt.label}
        </Typography>
      </Group>
      {checked && <IconCheck size={16} style={{ marginInlineStart: 'auto' }} />}
    </Group>
  )
}

const renderProjectOption: SelectProps['renderOption'] = ({ option, checked }) => {
  const opt = option as SelectData

  return (
    <Group wrap="nowrap" justify="space-between" sx={{ flex: 1 }} h={36}>
      <Group gap={8} wrap="nowrap" sx={{ flex: 1, minWidth: 0 }}>
        {getProjectTypeIcon(opt.projectType)}
        <Typography variant="title-md" fw={checked ? 500 : 400} sx={{ minWidth: 0 }}>
          {opt.label}
        </Typography>
      </Group>
      {checked && <IconCheck size={16} style={{ marginInlineStart: 'auto' }} />}
    </Group>
  )
}

export const renderRoleOption: SelectProps['renderOption'] = ({ option, checked }) => {
  const opt = option as SelectData

  return (
    <Group wrap="nowrap" justify="space-between" sx={{ flex: 1 }}>
      <Group gap={8} align="center" wrap="nowrap" sx={{ flex: 1, minWidth: 0 }}>
        {opt.icon && (
          <Typography fz={20} sx={{ lineHeight: 1 }}>
            {opt.icon}
          </Typography>
        )}
        <Stack gap={2} sx={{ minWidth: 0 }}>
          <Typography variant="title-md" fw={checked ? 500 : 400}>
            {opt.label}
          </Typography>
          {opt.description && (
            <Typography variant="body-lg" c="carbon.7">
              {opt.description}
            </Typography>
          )}
        </Stack>
      </Group>
      {checked && <IconCheck size={16} style={{ marginInlineStart: 'auto' }} />}
    </Group>
  )
}

export const ScopeRoleSelect = ({
  name,
  roleSelectProps,
  scopeSelectProps,
  defaultRole,
  scopeType,
  disabledTips
}: ScopeRoleSelectProps) => {
  const { control } = useFormContext()

  const { append, remove, fields } = useFieldArray({
    control,
    name
  })

  const liveData = useWatch({ control, name })

  const data = useMemo(
    () => fields.map((field, index) => ({ ...field, ...(liveData?.[index] || {}) })),
    [fields, liveData]
  )

  const usedScopes = useMemo(() => {
    return Array.from(new Set((data || []).map((item) => item.scope_id).filter(Boolean)))
  }, [data])

  const currentScopeOptions = useMemo(() => {
    return (scopeSelectProps?.data || []).map((option) => {
      return {
        ...option,
        disabled: usedScopes.includes(option.value)
      }
    })
  }, [scopeSelectProps?.data, usedScopes])

  const disabledAdd = usedScopes.length === (scopeSelectProps?.data?.length || 0)
  const selectedScopeOptions = useMemo(() => {
    return new Map((scopeSelectProps?.data || []).map((option) => [option.value, option]))
  }, [scopeSelectProps?.data])

  const addNewItem = () => {
    const availableScope = currentScopeOptions.find((option) => !option.disabled) ?? { label: '', value: '' }
    append({
      scope_type: scopeType,
      scope_id: availableScope?.value || '',
      rbac_role: defaultRole
    })
  }

  return (
    <Box>
      {data?.length > 0 ? (
        <Flex direction="column" gap="sm">
          {data.map((item, index) => (
            <Flex key={item.id || index} gap="sm" align="flex-start">
              <Box flex={1}>
                <FormSelect
                  size="sm"
                  w="100%"
                  name={`${name}.${index}.rbac_role`}
                  {...roleSelectProps}
                  h={40}
                  styles={{ input: { height: 40, minHeight: 40 } }}
                  renderOption={renderRoleOption}
                />
              </Box>
              <Box flex={1}>
                <FormSelect
                  size="sm"
                  w="100%"
                  name={`${name}.${index}.scope_id`}
                  {...scopeSelectProps}
                  data={currentScopeOptions}
                  h={40}
                  styles={{
                    input: { height: 40, minHeight: 40 },
                    option: { padding: '4px 8px' }
                  }}
                  leftSection={
                    scopeType === RoleScopeTypes.PROJECT ? (
                      getProjectTypeIcon(selectedScopeOptions.get(data?.[index]?.scope_id)?.projectType)
                    ) : data?.[index]?.scope_id ? (
                      <IconBezierCurve02 size={16} />
                    ) : undefined
                  }
                  renderOption={
                    scopeType === RoleScopeTypes.PROJECT
                      ? renderProjectOption
                      : scopeType === RoleScopeTypes.TIDB
                        ? renderInstanceOption
                        : undefined
                  }
                />
              </Box>
              <Box>
                <ActionIcon
                  variant="default"
                  size={40}
                  c="carbon.8"
                  onClick={() => remove(index)}
                  sx={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}
                >
                  <IconTrash01 size={16} />
                </ActionIcon>
              </Box>
            </Flex>
          ))}
        </Flex>
      ) : null}

      <Box mt={data?.length > 0 ? 'sm' : 0}>
        <HoverCard position="top" withArrow shadow="md" openDelay={200} disabled={!disabledAdd}>
          <HoverCard.Target>
            <Box display="inline-block">
              <Button
                variant="default"
                h={40}
                leftSection={<IconPlus size={16} />}
                onClick={addNewItem}
                disabled={disabledAdd}
              >
                Add Role and Select {scopeType === RoleScopeTypes.PROJECT ? 'Project' : 'Instance'}
              </Button>
            </Box>
          </HoverCard.Target>
          <HoverCard.Dropdown>{disabledTips}</HoverCard.Dropdown>
        </HoverCard>
      </Box>
    </Box>
  )
}
