import {
  Button,
  Card,
  Center,
  Group,
  Loader,
  notifier,
  SimpleGrid,
  Stack,
  TextInput,
  Typography,
  UnstyledButton
} from '@tidbcloud/uikit'
import { MRT_ColumnDef, ProTable } from '@tidbcloud/uikit/biz'
import { IconSearchLg } from '@tidbcloud/uikit/icons'
import { useCallback, useEffect, useMemo, useState } from 'react'

import { cloudConfigControllerGetTemplate } from 'apiClient/services/devops'
import {
  CloudConfigControllerGetTemplateClusterType,
  CloudconfigNamedParameter,
  CloudconfigTemplate,
  CloudconfigTemplateDefaultCase,
  CloudconfigTemplateParameters,
  CloudconfigClusterType
} from 'apiClient/services/devops/interface'

type TablePaginationState = {
  pageIndex: number
  pageSize: number
}

type TablePaginationUpdater =
  | TablePaginationState
  | ((prev: TablePaginationState) => TablePaginationState)

const PARAMETER_PAGE_SIZE = 30

const getFixedPagination = (
  updaterOrValue: TablePaginationUpdater,
  currentPagination: TablePaginationState
) => {
  const nextPagination =
    typeof updaterOrValue === 'function'
      ? updaterOrValue(currentPagination)
      : updaterOrValue

  return {
    pageIndex: nextPagination.pageIndex,
    pageSize: PARAMETER_PAGE_SIZE
  }
}

const getDisplayValue = (value: unknown) => {
  if (value === null || value === undefined || value === '') {
    return '-'
  }

  if (typeof value === 'object') {
    return JSON.stringify(value)
  }

  return String(value)
}

const getErrorContent = (error: any) =>
  error?.response?.data?.errmsg ||
  error?.response?.data?.message ||
  error?.message ||
  String(error)

const SECTION_TITLE_STYLE = {
  fontSize: 16,
  lineHeight: '24px'
}

const CONTENT_TEXT_STYLE = {
  fontSize: 14,
  lineHeight: '20px'
}

const DetailItem = ({
  label,
  value
}: {
  label: string
  value?: React.ReactNode
}) => (
  <Stack gap={2}>
    <Typography variant="label-lg" c="carbon.6" style={CONTENT_TEXT_STYLE}>
      {label}
    </Typography>
    <Typography variant="body-lg" style={CONTENT_TEXT_STYLE}>
      {value || '-'}
    </Typography>
  </Stack>
)

export default function TemplateView({
  template_id,
  cluster_type,
  with_default_cases
}: {
  template_id: string
  cluster_type: CloudconfigClusterType
  with_default_cases: boolean
}) {
  const [template, setTemplate] = useState<CloudconfigTemplate>()
  const [loading, setLoading] = useState<boolean>(false)
  const [errorContent, setErrorContent] = useState<string>()
  const [defaultCasesLoadFailed, setDefaultCasesLoadFailed] = useState(false)
  const [activeConfigType, setActiveConfigType] = useState<string>()
  const [paramSearch, setParamSearch] = useState<string>('')
  const [paramPagination, setParamPagination] = useState<TablePaginationState>({
    pageIndex: 0,
    pageSize: PARAMETER_PAGE_SIZE
  })

  const fetchTemplate = useCallback(async () => {
    setLoading(true)
    setErrorContent(undefined)
    setDefaultCasesLoadFailed(false)

    const requestTemplate = async (includeDefaultCases: boolean) =>
      (
        await cloudConfigControllerGetTemplate(template_id, {
          cluster_type:
            cluster_type as CloudConfigControllerGetTemplateClusterType,
          with_default_cases: includeDefaultCases
        })
      ).data

    try {
      const data = await requestTemplate(with_default_cases)
      setTemplate(data.template)
      setParamSearch('')
    } catch (error) {
      if (with_default_cases) {
        try {
          const data = await requestTemplate(false)
          setTemplate(data.template)
          setParamSearch('')
          setDefaultCasesLoadFailed(true)
          notifier.warn('Template details are loaded without default cases.', {
            title: 'Failed to load default cases'
          })
          return
        } catch (fallbackError) {
          const message = getErrorContent(fallbackError)
          setTemplate(undefined)
          setErrorContent(message)
          notifier.error(message, { title: 'Failed to load template' })
          return
        }
      }

      const message = getErrorContent(error)
      setTemplate(undefined)
      setErrorContent(message)
      notifier.error(message, { title: 'Failed to load template' })
    } finally {
      setLoading(false)
    }
  }, [cluster_type, template_id, with_default_cases])

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

  const columnsDefaultCase = useMemo<
    MRT_ColumnDef<CloudconfigTemplateDefaultCase>[]
  >(
    () => [
      {
        accessorFn: (record) => record.version || '-',
        header: 'Version',
        id: 'version',
        size: 150
      },
      {
        accessorFn: (record) => record.cloud_provider || '-',
        header: 'Cloud Provider',
        id: 'cloud_provider',
        size: 160
      },
      {
        accessorFn: (record) => getDisplayValue(record.instance_type),
        header: 'Instance Type',
        id: 'instance_type',
        size: 180
      }
    ],
    []
  )

  const columns = useMemo<MRT_ColumnDef<UnifyParam>[]>(
    () => [
      {
        accessorFn: (record) => record.param.name || '-',
        header: 'Name',
        id: 'name',
        size: 260
      },
      {
        Cell: ({ row }) => (
          <Typography
            variant="body-lg"
            style={{
              ...CONTENT_TEXT_STYLE,
              overflowWrap: 'anywhere',
              whiteSpace: 'pre-wrap',
              wordBreak: 'break-word'
            }}
          >
            {getDisplayValue(row.original.param.value)}
          </Typography>
        ),
        header: 'Value',
        id: 'value',
        size: 360
      },
      {
        accessorFn: (record) => record.param.comment || '-',
        header: 'Comment',
        id: 'comment',
        size: 360
      }
    ],
    []
  )

  const configTypeToParams = useMemo(() => {
    const params: Record<string, CloudconfigTemplateParameters> = {}

    if (template?.tags?.template_type === 'custom') {
      for (const key in template?.custom_template_info?.data) {
        params[key] = template?.custom_template_info?.data[key].parameters || {}
      }
    } else {
      params[template?.config_type || ''] = template?.parameters || {}
    }

    return params
  }, [template])

  const configTypes = useMemo(
    () => Object.keys(configTypeToParams).filter(Boolean),
    [configTypeToParams]
  )

  useEffect(() => {
    if (
      configTypes.length > 0 &&
      (!activeConfigType || !configTypes.includes(activeConfigType))
    ) {
      setActiveConfigType(configTypes[0])
    }
  }, [activeConfigType, configTypes])

  useEffect(() => {
    setParamPagination((current) => ({ ...current, pageIndex: 0 }))
  }, [activeConfigType, paramSearch])

  const paramRows = useMemo(
    () =>
      mapToList(
        configTypeToParams[activeConfigType || ''],
        activeConfigType
      ).filter((param) => param.param.name?.includes(paramSearch)),
    [activeConfigType, configTypeToParams, paramSearch]
  )

  if (loading) {
    return (
      <Center h={300}>
        <Loader />
      </Center>
    )
  }

  if (errorContent) {
    return (
      <Card withBorder shadow="xs" padding="md" radius="sm">
        <Center h={220}>
          <Stack gap="sm" align="center">
            <Typography variant="title-lg" style={SECTION_TITLE_STYLE}>
              Failed to load template
            </Typography>
            <Typography
              variant="body-lg"
              c="carbon.6"
              style={CONTENT_TEXT_STYLE}
            >
              {errorContent}
            </Typography>
            <Button variant="default" onClick={fetchTemplate}>
              Retry
            </Button>
          </Stack>
        </Center>
      </Card>
    )
  }

  const shouldPaginateParams = paramRows.length > PARAMETER_PAGE_SIZE

  return (
    <Stack gap="md">
      <Card withBorder shadow="xs" padding="md" radius="sm">
        <Stack gap="md">
          <Typography variant="title-lg" style={SECTION_TITLE_STYLE}>
            Information
          </Typography>
          <SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md">
            <DetailItem label="ID" value={template_id} />
            <DetailItem label="Name" value={template?.name} />
            <DetailItem label="Config Type" value={template?.config_type} />
          </SimpleGrid>
        </Stack>
      </Card>

      <Card withBorder shadow="xs" padding="md" radius="sm">
        <Stack gap="md">
          <Group justify="space-between" align="flex-end">
            <Stack gap={4}>
              <Typography variant="title-lg" style={SECTION_TITLE_STYLE}>
                Parameters
              </Typography>
              <Group gap={4}>
                {configTypes.map((configType) => {
                  const active = activeConfigType === configType

                  return (
                    <UnstyledButton
                      key={configType}
                      onClick={() => setActiveConfigType(configType)}
                      style={{
                        borderBottom: active
                          ? '2px solid var(--mantine-color-peacock-6, #0b6fcb)'
                          : '2px solid transparent',
                        borderRadius: 0,
                        color: active
                          ? 'var(--mantine-color-carbon-9, #1f2d3d)'
                          : 'var(--mantine-color-carbon-6, #5f6b7a)',
                        fontSize: 14,
                        fontWeight: active ? 600 : 400,
                        lineHeight: '20px',
                        minHeight: 32,
                        paddingLeft: 12,
                        paddingRight: 12
                      }}
                    >
                      {configType}
                    </UnstyledButton>
                  )
                })}
              </Group>
            </Stack>

            <TextInput
              leftSection={<IconSearchLg size={16} />}
              placeholder="Search parameters"
              value={paramSearch}
              onChange={(event) => setParamSearch(event.target.value)}
              style={{ width: 280 }}
            />
          </Group>

          {paramRows.length === 0 ? (
            <Center h={120}>
              <Typography
                variant="body-lg"
                c="carbon.6"
                style={CONTENT_TEXT_STYLE}
              >
                Empty Template
              </Typography>
            </Center>
          ) : (
            <ProTable<UnifyParam>
              columns={columns}
              data={paramRows}
              enableColumnActions={false}
              enableColumnFilters={false}
              enableDensityToggle={false}
              enableFullScreenToggle={false}
              enableHiding={false}
              enablePagination={shouldPaginateParams}
              enableSorting={false}
              enableTopToolbar={false}
              getRowId={(row, rowIndex) =>
                [row.filename, row.param.name, rowIndex].join('|')
              }
              onPaginationChange={(updaterOrValue) => {
                setParamPagination((currentPagination) =>
                  getFixedPagination(
                    updaterOrValue as TablePaginationUpdater,
                    currentPagination
                  )
                )
              }}
              pagination={{ showRowsPerPage: false }}
              rowCount={shouldPaginateParams ? paramRows.length : undefined}
              state={{ pagination: paramPagination }}
            />
          )}
        </Stack>
      </Card>

      {with_default_cases && !defaultCasesLoadFailed && (
        <Card withBorder shadow="xs" padding="md" radius="sm">
          <Stack gap="md">
            <Typography variant="title-lg" style={SECTION_TITLE_STYLE}>
              Default For
            </Typography>
            <ProTable<CloudconfigTemplateDefaultCase>
              columns={columnsDefaultCase}
              data={template?.default_cases || []}
              enableColumnActions={false}
              enableColumnFilters={false}
              enableDensityToggle={false}
              enableFullScreenToggle={false}
              enableHiding={false}
              enablePagination={false}
              enableSorting={false}
              enableTopToolbar={false}
              getRowId={(row, rowIndex) =>
                [
                  row.version,
                  row.cloud_provider,
                  row.instance_type,
                  rowIndex
                ].join('|')
              }
            />
          </Stack>
        </Card>
      )}
    </Stack>
  )
}

export type UnifyParam = {
  key: string
  filename: string
  param: CloudconfigNamedParameter
}

const mapToList = (
  m: CloudconfigTemplateParameters | undefined,
  filename?: string | undefined
) => {
  if (m && filename) {
    const list: UnifyParam[] = []
    Object.keys(m).forEach((key) => {
      const param = m[key]
      list.push({ filename, key: param.name!, param })
    })
    return list
  }
  return []
}
