import {
  Box,
  Group,
  Stack,
  ActionIcon,
  TextInput,
  Modal,
  SimpleGrid,
  Typography,
  Collapse,
  Loader,
  UnstyledButton,
  Text,
  Button,
  Divider
} from '@tidbcloud/uikit'
import { FormTextInput, Form, FormSelect } from '@tidbcloud/uikit/biz'
import { IconChevronDown, IconChevronUp, IconColon, IconPlus, IconTrash01 } from '@tidbcloud/uikit/icons'
import { useEffect, useMemo, useState } from 'react'
import { useForm, useFormContext } from 'react-hook-form'
import { useParams } from 'react-router-dom'

import { FormInput } from 'dbaas/components/Form'
import { TagGroupItemView } from 'dbaas/components/tag'
import { CloudProviderLabelConst } from 'dbaas/features/Project'
import { FormItem } from 'dbaas/screens/NextGen/my-tidb-creation/shared/FormItem'
import { GetOrgInfoQueryResult, useListWarehouseSizes } from 'dbaas/services/warehouse'
import useStores from 'dbaas/stores/useStores'

import { CreateWarehouseRequestBody } from './WarehouseCreate'

interface BasicSettingsSectionProps {
  orgInfo?: GetOrgInfoQueryResult
}

export const BasicSettingsSection = ({ orgInfo }: BasicSettingsSectionProps) => {
  const { id: warehouseId } = useParams<{ id: string }>()

  const [isTagsModalOpen, setIsTagsModalOpen] = useState(false)
  const [tags, setTags] = useState<Array<{ key: string; value: string }>>([{ key: '', value: '' }])
  const [tagErrors, setTagErrors] = useState<Array<{ key?: string; value?: string }>>([
    { key: undefined, value: undefined }
  ])
  const [tagLimitError, setTagLimitError] = useState<string | undefined>(undefined)
  const MAX_TAGS = 10
  const { setValue, watch } = useFormContext<CreateWarehouseRequestBody>()

  const tagsForm = useForm({
    reValidateMode: 'onChange'
  })

  // Close modal and clear only modal-local inputs/errors so that main form
  // stored `tags` remain intact but modal inputs are empty on next open.
  const handleCloseTagsModal = () => {
    tagsForm.reset()
    setTags([{ key: '', value: '' }])
    setTagErrors([{}])
    setTagLimitError(undefined)
    setIsTagsModalOpen(false)
  }

  // helper: normalize stored tags (stringified object or object) to array of {key, value}
  const normalizeStoredTags = (raw: any): Array<{ key: string; value: string }> => {
    if (!raw) return []
    if (typeof raw === 'string') {
      try {
        const p = JSON.parse(raw)
        if (Array.isArray(p)) return p.map((it) => ({ key: it.key ?? '', value: it.value ?? '' }))
        if (p && typeof p === 'object') return Object.entries(p).map(([k, v]) => ({ key: k, value: String(v ?? '') }))
        return []
      } catch (_e) {
        return []
      }
    }
    if (Array.isArray(raw)) return raw.map((it) => ({ key: it.key ?? '', value: it.value ?? '' }))
    if (raw && typeof raw === 'object') return Object.entries(raw).map(([k, v]) => ({ key: k, value: String(v ?? '') }))
    return []
  }

  const addTag = () => {
    // remaining slots based on already-saved tags (tagList)
    const remaining = Math.max(0, MAX_TAGS - tagList.length)
    if (remaining <= 0 || tags.length >= remaining) {
      setTagLimitError(`You can add up to ${remaining} more tags`)
      return
    }
    setTags((s) => [...s, { key: '', value: '' }])
    setTagErrors((s) => [...s, {}])
    setTagLimitError(undefined)
  }

  const removeTag = (index: number) => {
    setTags((s) => s.filter((_, i) => i !== index))
    setTagErrors((s) => s.filter((_, i) => i !== index))
    // clear limit error when removing
    setTagLimitError(undefined)
  }

  const updateTag = (index: number, field: 'key' | 'value', value: string) =>
    setTags((s) => s.map((t, i) => (i === index ? { ...t, [field]: value } : t)))

  const tagsVal = watch('tags')
  const tagList = useMemo(() => {
    return normalizeStoredTags(tagsVal)
  }, [tagsVal])

  const onSave = async () => {
    // validate tags: key/value must be non-empty, key must not be duplicated
    const errors: Array<{ key?: string; value?: string }> = tags.map(() => ({}))

    // check empty
    tags.forEach((t, i) => {
      if (!t.key || t.key.trim() === '') errors[i].key = 'Key is required'
      if (!t.value || t.value.trim() === '') errors[i].value = 'Value is required'
    })

    // check duplicates for keys: only mark later occurrences as duplicate
    const seen: Record<string, boolean> = {}
    tags.forEach((t, i) => {
      const k = t.key?.trim() ?? ''
      if (k === '') return
      if (seen[k]) {
        errors[i].key = errors[i].key ? errors[i].key + '; Duplicate key' : 'Duplicate key'
      } else {
        seen[k] = true
      }
    })

    const hasError = errors.some((e) => e.key || e.value)
    if (hasError) {
      setTagErrors(errors)
      return
    }

    // transform modal tags array into { key: value }
    const tagsObj: Record<string, string> = {}
    tags.forEach((t) => {
      const k = t.key?.trim() ?? ''
      if (k !== '') tagsObj[k] = t.value ?? ''
    })

    // parse existing stored tags (may be stringified or object) and merge
    const existingRaw = tagsVal
    const existingObj: Record<string, string> = {}
    if (existingRaw) {
      try {
        if (typeof existingRaw === 'string') {
          const parsed = JSON.parse(existingRaw)
          if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
            Object.entries(parsed).forEach(([k, v]) => {
              existingObj[k] = String(v ?? '')
            })
          }
        } else if (typeof existingRaw === 'object') {
          Object.entries(existingRaw).forEach(([k, v]) => {
            existingObj[k] = String(v ?? '')
          })
        }
      } catch (_e) {
        // ignore parse errors and treat as empty
      }
    }

    // Merge: modal-entered tags override existing keys, keep others
    const merged = { ...existingObj, ...tagsObj }

    setValue('tags', JSON.stringify(merged) as any)

    // clear errors and close modal (also clears modal inputs)
    setTagErrors(tags.map(() => ({})))
    handleCloseTagsModal()
  }

  // Remove a tag from the stored `tags` field (persisted in the main form)
  const removeStoredTag = (keyToRemove: string) => {
    const existingRaw = tagsVal
    const existingObj: Record<string, string> = {}
    if (existingRaw) {
      try {
        if (typeof existingRaw === 'string') {
          const parsed = JSON.parse(existingRaw)
          if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
            Object.entries(parsed).forEach(([k, v]) => {
              existingObj[k] = String(v ?? '')
            })
          } else if (Array.isArray(parsed)) {
            parsed.forEach((it: any) => {
              if (it && it.key) existingObj[it.key] = it.value ?? ''
            })
          }
        } else if (Array.isArray(existingRaw)) {
          existingRaw.forEach((it: any) => {
            if (it && it.key) existingObj[it.key] = it.value ?? ''
          })
        } else if (typeof existingRaw === 'object') {
          Object.entries(existingRaw).forEach(([k, v]) => {
            existingObj[k] = String(v ?? '')
          })
        }
      } catch (_e) {
        // ignore parse errors
      }
    }

    if (existingObj.hasOwnProperty(keyToRemove)) {
      delete existingObj[keyToRemove]
      try {
        const hasAny = Object.keys(existingObj).length > 0
        if (hasAny) setValue('tags', JSON.stringify(existingObj) as any)
        else setValue('tags', '' as any)
      } catch (_e) {
        // noop
      }
    }
  }

  return (
    <FormItem
      label="Basic Setting"
      description={
        <Box>
          Set the name of your new warehouse, cloud provider and region are only support{' '}
          <b>{CloudProviderLabelConst[orgInfo?.data?.storageInfo?.provider ?? ''] ?? '-'}</b> and{' '}
          <b>{orgInfo?.data?.storageInfo?.regionTitle ?? '-'}</b>.
        </Box>
      }
    >
      <Stack gap="md">
        <FormTextInput name="name" disabled={!!warehouseId} label="Warehouse Name" placeholder="Enter warehouse name" />

        <Group align="flex-start">
          {tagList.map((t, idx) => (
            <TagGroupItemView
              key={idx}
              item={{
                id: `${idx}`,
                label: `${t.key}: ${t.value}`,
                withRemove: true,
                onRemove: () => removeStoredTag(t.key)
              }}
            />
          ))}

          <UnstyledButton>
            <Text
              size="sm"
              fw={500}
              c={Math.max(0, MAX_TAGS - tagList.length) <= 0 ? 'dimmed' : 'peacock.7'}
              className={Math.max(0, MAX_TAGS - tagList.length) <= 0 ? 'wd-cursor-not-allowed' : ''}
              onClick={() => {
                // Calculate remaining slots based on already-saved tags and MAX_TAGS.
                const existingCount = tagList.length
                const remaining = Math.max(0, MAX_TAGS - existingCount)
                if (remaining <= 0) {
                  setTagLimitError(`You can add up to ${MAX_TAGS} tags`) // or a more specific message
                  return
                }
                // initialize modal with a single empty row (do not preload saved tags)
                setTags([{ key: '', value: '' }])
                setTagErrors([{}])
                setTagLimitError(undefined)
                setIsTagsModalOpen(true)
              }}
            >
              Add Tags for Your Warehouse
            </Text>
          </UnstyledButton>
        </Group>
      </Stack>

      <FormInput name="tags" type="hidden" />

      <Modal
        opened={isTagsModalOpen}
        size={650}
        title="Add Tags for Your Warehouse"
        centered
        closeOnClickOutside={false}
        onClose={handleCloseTagsModal}
      >
        <Form onSubmit={() => {}} form={tagsForm} onCancel={handleCloseTagsModal} withActions={false}>
          <Typography c="carbon.7">Tags help organize your warehouse (e.g., environment:prod).</Typography>
          <Stack gap="sm">
            {tags.map((t, i) => (
              <Group key={i} align="flex-start" gap={4}>
                <TextInput
                  placeholder="Enter key"
                  value={t.key}
                  onChange={(e) => {
                    updateTag(i, 'key', e.target.value)
                    // clear existing error for this field as user types
                    setTagErrors((s) => s.map((err, idx) => (idx === i ? { ...err, key: undefined } : err)))
                  }}
                  sx={{ flex: 1 }}
                  error={tagErrors[i]?.key}
                />
                <ActionIcon sx={{ p: 0 }} h={40}>
                  <IconColon size={16} />
                </ActionIcon>
                <TextInput
                  placeholder="Enter Value"
                  value={t.value}
                  onChange={(e) => {
                    updateTag(i, 'value', e.target.value)
                    setTagErrors((s) => s.map((err, idx) => (idx === i ? { ...err, value: undefined } : err)))
                  }}
                  sx={{ flex: 1 }}
                  error={tagErrors[i]?.value}
                />
                {i === 0 ? (
                  <ActionIcon
                    variant="outline"
                    size="40"
                    ml={8}
                    onClick={() => addTag()}
                    aria-label={`Add tag ${i}`}
                    disabled={tags.length >= Math.max(0, MAX_TAGS - tagList.length)}
                  >
                    <IconPlus size={18} />
                  </ActionIcon>
                ) : (
                  <ActionIcon
                    variant="outline"
                    size="40"
                    ml={8}
                    onClick={() => removeTag(i)}
                    aria-label={`Remove tag ${i}`}
                  >
                    <IconTrash01 size={18} />
                  </ActionIcon>
                )}
              </Group>
            ))}
          </Stack>
          {tagLimitError && <Box style={{ color: 'red', marginTop: 8 }}>{tagLimitError}</Box>}

          <Divider mx="-24" />
          <Group justify="flex-end">
            <Button variant="outline" onClick={handleCloseTagsModal}>
              Cancel
            </Button>
            <Button onClick={onSave}>Save</Button>
          </Group>
        </Form>
      </Modal>
    </FormItem>
  )
}

const SizeItem = ({ selected, onClick, size }) => {
  return (
    <Group
      mod={{ selected: selected }}
      sx={(t) => ({
        border: `1px solid ${t.colors.carbon[4]}`,
        borderRadius: t.defaultRadius,
        cursor: 'pointer',
        boxSizing: 'border-box',
        padding: '12px 24px',
        '&:hover': {
          borderColor: t.colors.carbon[6]
        },
        '&[data-selected]': {
          borderColor: t.colors.carbon[9],
          borderWidth: 2,
          padding: `11px 23px`
        },
        '&:not([data-disabled],[data-selected]):hover': {
          borderColor: t.colors.carbon[6]
        }
      })}
      justify="space-between"
      onClick={onClick}
    >
      <Typography variant="title-lg" c="carbon.7">
        {size.name}
      </Typography>
      <Typography variant="title-md" c="carbon.7">
        {size.creditCurrency}
        {size.creditCostPerHour}/hour
      </Typography>
    </Group>
  )
}

export const SizeSettingsSection = () => {
  const {
    store: {
      lastVisitLocation: { orgId }
    }
  } = useStores()
  const DEFAULT_SHOW_SIZE = 6
  const [showMoreOpened, setShowMoreOpened] = useState(false)
  const { setValue, getValues, watch } = useFormContext<CreateWarehouseRequestBody>()
  const { data, isLoading } = useListWarehouseSizes(orgId)
  const curSize = watch('size')

  useEffect(() => {
    if (!curSize && data?.data?.length) {
      setValue('size', JSON.stringify(data.data[0]))
    } else if (curSize && data?.data?.length) {
      const size = JSON.parse(curSize)
      const matched = data.data.find((s) => s.value === size.value)
      if (matched) {
        setValue('size', JSON.stringify(matched))
      }
    }
  }, [data, curSize, setValue, getValues])

  return (
    <FormItem
      label="Warehouse Size"
      description={
        <Box>
          learn more about the{' '}
          <a
            href="https://docs.tidb.io/tidbcloudlake/warehouse/"
            target="_blank"
            rel="noreferrer"
            data-force-keep-doc-link
          >
            details of warehouse size specifications
          </a>
        </Box>
      }
    >
      <FormInput name="size" type="hidden" />
      <FormInput name="price" type="hidden" />
      {isLoading ? (
        <Loader size="sm" />
      ) : (
        <>
          <Stack gap="md">
            <SimpleGrid cols={2}>
              {data?.data?.slice(0, DEFAULT_SHOW_SIZE).map((size, idx) => (
                <SizeItem
                  key={idx}
                  selected={curSize && JSON.parse(curSize)?.value === size.value}
                  size={size}
                  onClick={() => {
                    setValue('size', JSON.stringify(size))
                  }}
                />
              ))}
            </SimpleGrid>
          </Stack>

          <Collapse in={showMoreOpened}>
            <SimpleGrid cols={2} mt="md">
              {data?.data?.slice(DEFAULT_SHOW_SIZE)?.map((size, idx) => (
                <SizeItem
                  key={idx}
                  selected={curSize && JSON.parse(curSize)?.value === size.value}
                  size={size}
                  onClick={() => {
                    setValue('size', JSON.stringify(size))
                  }}
                />
              ))}
            </SimpleGrid>
          </Collapse>

          {(data?.data?.length ?? 0) > DEFAULT_SHOW_SIZE && (
            <Group
              gap={4}
              mt="md"
              sx={{ cursor: 'pointer', userSelect: 'none' }}
              onClick={() => setShowMoreOpened((o) => !o)}
            >
              <Typography variant="action-md" fw={500}>
                Show {showMoreOpened ? 'Less' : 'More'} Size
              </Typography>
              {showMoreOpened ? <IconChevronUp size={16} c="peacock" /> : <IconChevronDown size={16} c="peacock" />}
            </Group>
          )}
        </>
      )}
    </FormItem>
  )
}

export const SuspendSettingsSection = () => {
  return (
    <FormItem label="Auto Suspend">
      <Group wrap="nowrap" align="flex-start" gap={32}>
        <Typography component="div" variant="body-lg" c="carbon.7">
          Automatically suspend inactive warehouses that have not processed query tasks for a certain period of time.
          The suspended warehouses do not generate any costs.
        </Typography>
        <FormSelect
          name="autoSuspend"
          data={[
            { label: '5 mins', value: `${60 * 5}` },
            { label: '10 mins', value: `${60 * 10}` },
            { label: '15 mins', value: `${60 * 15}` },
            { label: '30 mins', value: `${60 * 30}` },
            { label: '1 hour', value: `${60 * 60}` },
            { label: 'never', value: `0` }
          ]}
        />
      </Group>
    </FormItem>
  )
}
