import {
  ActionIcon,
  Button,
  Center,
  Group,
  Loader,
  Select,
  type SelectProps,
  Stack,
  Textarea,
  TextInput,
  type TextInputProps,
  Tooltip
} from '@tidbcloud/uikit'
import { MRT_ColumnDef, ProTable } from '@tidbcloud/uikit/biz'
import { IconPlus, IconTrash01 } from '@tidbcloud/uikit/icons'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'

import { cloudConfigControllerListParameterAttributes } from 'apiClient/services/devops'
import {
  CloudconfigClusterType,
  CloudconfigParameterAttribute
} from 'apiClient/services/devops/interface'
import { parseFormValue } from 'pages/Tenants/ClusterDetail/Configs/CurrentConfig/Current'
import { convertToString } from 'pages/Tenants/ClusterDetail/Configs/Forms/PreviewForm'
import { sanitizeConfigIdentifier } from 'utils/string'

export interface ParameterValue {
  value: any
  type: string | undefined
}

export interface ParameterManagerProps {
  configType: string
  version: string
  selectedParams: Record<string, ParameterValue>
  onParameterChange: (name: string, value: ParameterValue) => void
  onParameterRemove: (name: string) => void
  clusterType?: CloudconfigClusterType
}

type EditingColumn = 'name' | 'type' | 'value' | null

type ParameterRow = {
  key: string
  name: string
  type: string | null | undefined
  value: any
}

const TYPE_OPTIONS = [
  { label: 'string', value: 'string' },
  { label: 'int', value: 'int' },
  { label: 'float', value: 'float' },
  { label: 'json', value: 'json' },
  { label: 'bool', value: 'bool' }
]

const BOOL_OPTIONS = [
  { label: 'true', value: 'true' },
  { label: 'false', value: 'false' }
]

const COMPACT_TEXT_INPUT_STYLES: TextInputProps['styles'] = {
  input: {
    fontSize: 12,
    '&::placeholder': {
      fontSize: 12
    }
  }
}

const TYPE_SELECT_COMBOBOX_PROPS: SelectProps['comboboxProps'] = {
  withinPortal: true,
  zIndex: 2000
}

const getParameterRowKey = (name: string) => name || '__new_parameter__'

const ParameterManager = ({
  configType,
  version,
  selectedParams,
  clusterType,
  onParameterChange,
  onParameterRemove
}: ParameterManagerProps) => {
  const [availableParams, setAvailableParams] = useState<
    CloudconfigParameterAttribute[]
  >([])
  const [loading, setLoading] = useState(false)
  const [editingRowKey, setEditingRowKey] = useState<string | null>(null)
  const [editingColumn, setEditingColumn] = useState<EditingColumn>(null)
  const [parameterSearch, setParameterSearch] = useState('')
  const parameterRequestRef = useRef(0)

  const loadParameters = useCallback(async () => {
    const requestId = ++parameterRequestRef.current

    setAvailableParams([])
    setParameterSearch('')
    setLoading(true)
    try {
      const res = await cloudConfigControllerListParameterAttributes(
        configType,
        version,
        {
          cluster_type: clusterType || CloudconfigClusterType.DEDICATED_TIDB
        }
      )

      if (requestId === parameterRequestRef.current) {
        setAvailableParams(res.data.items || [])
      }
    } catch (error) {
      if (requestId === parameterRequestRef.current) {
        setAvailableParams([])
        console.error('Failed to load parameters:', error)
      }
    } finally {
      if (requestId === parameterRequestRef.current) {
        setLoading(false)
      }
    }
  }, [clusterType, configType, version])

  useEffect(() => {
    void loadParameters()
  }, [loadParameters])

  const tableData = useMemo<ParameterRow[]>(
    () => [
      ...Object.entries(selectedParams).map(([name, value]) => ({
        key: getParameterRowKey(name),
        name,
        type: value.type,
        value: value.value
      })),
      { key: 'NEW', name: 'NEW', type: null, value: null }
    ],
    [selectedParams]
  )

  const isEditingRow = useCallback(
    (record: ParameterRow) => record.key === editingRowKey,
    [editingRowKey]
  )

  const isEditingCol = useCallback(
    (record: ParameterRow, col: EditingColumn) =>
      isEditingRow(record) && editingColumn === col,
    [editingColumn, isEditingRow]
  )

  const parameterOptions = useMemo(
    () =>
      availableParams
        .filter((param) => param.name && !selectedParams[param.name])
        .map((param) => ({
          label: param.name || '',
          value: param.name || ''
        })),
    [availableParams, selectedParams]
  )

  const columns = useMemo<MRT_ColumnDef<ParameterRow>[]>(
    () => [
      {
        Cell: ({ row }) => {
          const record = row.original
          const index = row.index

          if (record.name === 'NEW') {
            return (
              <Button
                leftSection={<IconPlus size={16} />}
                variant="default"
                onClick={() => {
                  const newName =
                    configType === 'INIT_SQL' ? `Paragraph_${index + 1}` : ''
                  onParameterChange(newName, { value: '', type: 'string' })
                  setParameterSearch(newName)
                  setEditingRowKey(getParameterRowKey(newName))
                  setEditingColumn(configType === 'INIT_SQL' ? 'value' : 'name')
                }}
              >
                Add Parameter
              </Button>
            )
          }

          if (configType === 'INIT_SQL') {
            return `Paragraph_${index + 1}`
          }

          if (isEditingCol(record, 'name')) {
            if (
              parameterOptions.length > 0 &&
              (clusterType === CloudconfigClusterType.DEDICATED_TIDB ||
                clusterType === CloudconfigClusterType.SHARED_POOL)
            ) {
              const allowCustomParameter =
                clusterType === CloudconfigClusterType.SHARED_POOL

              return (
                <Select
                  autoFocus
                  creatable={allowCustomParameter}
                  data={parameterOptions}
                  defaultDropdownOpened
                  getCreateLabel={(query) => `Use custom parameter "${query}"`}
                  placeholder="Select parameter"
                  searchable
                  searchValue={parameterSearch}
                  value={record.name || null}
                  onCreate={(query) => {
                    const value = sanitizeConfigIdentifier(query)
                    return value ? { label: value, value } : null
                  }}
                  onSearchChange={(query) =>
                    setParameterSearch(sanitizeConfigIdentifier(query))
                  }
                  onChange={(value) => {
                    if (!value) {
                      return
                    }

                    const target = availableParams.find(
                      (param) => param.name === value
                    )
                    onParameterChange(value, {
                      type: target?.type || 'string',
                      value: target ? target.default_value : ''
                    })
                    onParameterRemove(record.name)
                    setParameterSearch('')
                    setEditingColumn('type')
                    setEditingRowKey(getParameterRowKey(value))
                  }}
                />
              )
            }

            return (
              <TextInput
                autoFocus
                placeholder="Press Enter to confirm parameter name"
                styles={COMPACT_TEXT_INPUT_STYLES}
                value={parameterSearch}
                onChange={(event) =>
                  setParameterSearch(
                    sanitizeConfigIdentifier(event.currentTarget.value)
                  )
                }
                onKeyDown={(event) => {
                  if (event.key !== 'Enter') {
                    return
                  }

                  const value = parameterSearch
                  if (value && value !== record.name) {
                    onParameterChange(value, {
                      type: record.type || undefined,
                      value: record.value
                    })
                    onParameterRemove(record.name)
                    setEditingRowKey(getParameterRowKey(value))
                  }
                  setEditingColumn('type')
                }}
              />
            )
          }

          return record.name
        },
        header: 'Parameter',
        id: 'name',
        size: 280
      },
      {
        Cell: ({ row }) => {
          const record = row.original

          const openTypeEditor = () => {
            if (record.name === 'NEW') {
              return
            }

            setEditingRowKey(record.key)
            setEditingColumn('type')
          }
          const isEditingType = isEditingCol(record, 'type')

          if (isEditingRow(record) && !isEditingCol(record, 'name')) {
            return (
              <Select
                autoFocus={isEditingType}
                comboboxProps={TYPE_SELECT_COMBOBOX_PROPS}
                data={TYPE_OPTIONS}
                defaultDropdownOpened={isEditingType}
                value={record.type || 'string'}
                onBlur={() => {
                  if (isEditingType) {
                    setEditingColumn('value')
                  }
                }}
                onChange={(value) => {
                  onParameterChange(record.name, {
                    type: value || 'string',
                    value: record.value
                  })
                  setEditingColumn('value')
                }}
              />
            )
          }

          if (record.name === 'NEW') {
            return null
          }

          return (
            <span
              role="button"
              style={{ cursor: 'pointer' }}
              tabIndex={0}
              onClick={openTypeEditor}
              onKeyDown={(event) => {
                if (event.key !== 'Enter' && event.key !== ' ') {
                  return
                }

                event.preventDefault()
                openTypeEditor()
              }}
            >
              {record.type || ''}
            </span>
          )
        },
        header: 'Type',
        id: 'type',
        size: 130
      },
      {
        Cell: ({ row }) => {
          const record = row.original

          if (!isEditingRow(record)) {
            return convertToString(record.value)
          }

          if (isEditingCol(record, 'value')) {
            if (configType === 'INIT_SQL') {
              return (
                <Textarea
                  autosize
                  minRows={3}
                  maxRows={10}
                  value={convertToString(record.value)}
                  style={{ minWidth: 300 }}
                  onBlur={() => {
                    setEditingColumn(null)
                    setEditingRowKey(null)
                  }}
                  onChange={(event) =>
                    onParameterChange(record.name, {
                      type: 'string',
                      value: event.target.value
                    })
                  }
                />
              )
            }

            if (record.type === 'bool') {
              return (
                <Select
                  autoFocus
                  data={BOOL_OPTIONS}
                  value={String(record.value)}
                  onChange={(value) => {
                    onParameterChange(record.name, {
                      type: record.type || undefined,
                      value: value === 'true'
                    })
                    setEditingColumn(null)
                    setEditingRowKey(null)
                  }}
                />
              )
            }

            return (
              <TextInput
                autoFocus
                value={convertToString(record.value)}
                placeholder="Press Enter to confirm value"
                onChange={(event) => {
                  let parsed: any
                  try {
                    parsed = parseFormValue(
                      record.type || undefined,
                      event.target.value
                    )

                    if (
                      Number.isNaN(parsed) &&
                      (record.type === 'int' || record.type === 'float')
                    ) {
                      parsed = ''
                    }
                  } catch (error) {
                    parsed = event.target.value
                  } finally {
                    onParameterChange(record.name, {
                      type: record.type || undefined,
                      value: parsed
                    })
                  }
                }}
                onKeyDown={(event) => {
                  if (event.key === 'Enter') {
                    setEditingColumn(null)
                    setEditingRowKey(null)
                  }
                }}
              />
            )
          }

          return convertToString(record.value)
        },
        header: 'Value',
        id: 'value',
        size: 360
      },
      {
        Cell: ({ row }) => {
          const record = row.original

          if (record.name === 'NEW') {
            return null
          }

          return (
            <Group gap={8} wrap="nowrap">
              <Tooltip label="Delete parameter">
                <ActionIcon
                  aria-label="Delete parameter"
                  color="red"
                  variant="subtle"
                  onClick={() => onParameterRemove(record.name)}
                >
                  <IconTrash01 size={16} />
                </ActionIcon>
              </Tooltip>
            </Group>
          )
        },
        header: 'Action',
        id: 'action',
        size: 90
      }
    ],
    [
      availableParams,
      clusterType,
      configType,
      isEditingCol,
      isEditingRow,
      onParameterChange,
      onParameterRemove,
      parameterOptions
    ]
  )

  if (loading) {
    return (
      <Center h={200}>
        <Stack align="center" gap="sm">
          <Loader />
        </Stack>
      </Center>
    )
  }

  return (
    <ProTable<ParameterRow>
      columns={columns}
      data={tableData}
      enableColumnActions={false}
      enableColumnFilters={false}
      enableDensityToggle={false}
      enableFullScreenToggle={false}
      enableHiding={false}
      enablePagination={false}
      enableSorting={false}
      enableTopToolbar={false}
      getRowId={(row) => row.key}
    />
  )
}

export default ParameterManager
