import {
  ActionIcon,
  Button,
  Card,
  Group,
  Modal,
  notifier,
  Select,
  SimpleGrid,
  Stack,
  TextInput,
  Tooltip,
  Typography
} from '@tidbcloud/uikit'
import { MRT_ColumnDef, ProTable } from '@tidbcloud/uikit/biz'
import { IconRefreshCcw01, IconSearchLg } from '@tidbcloud/uikit/icons'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { Link } from 'react-router-dom'

import {
  cloudConfigControllerDeleteTemplateDefaultCaseBindingByOp,
  cloudConfigControllerListAvailableClusterVersions,
  cloudConfigControllerListConfigTypes,
  cloudConfigControllerListInstanceTypes,
  cloudConfigControllerListTemplateDefaultCaseBindings
} from 'apiClient/services/devops'
import {
  CloudconfigTemplateDefaultCaseBinding,
  CloudconfigCloudInstanceType,
  CloudConfigControllerListInstanceTypesParams,
  CloudConfigControllerListTemplateDefaultCaseBindingsClusterType,
  CloudconfigClusterType,
  CloudConfigControllerListTemplateDefaultCaseBindingsParams
} from 'apiClient/services/devops/interface'

import TemplateView from './TemplateView'

type DefaultTemplateFilters = Omit<
  CloudConfigControllerListTemplateDefaultCaseBindingsParams,
  'page' | 'per_page'
>

type DefaultTemplateHiddenFilter = 'cluster_type' | 'tenant_id'

type TablePaginationState = {
  pageIndex: number
  pageSize: number
}

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

const DEFAULT_TEMPLATE_PAGE_SIZE = 10

const CLUSTER_TYPE_OPTIONS = [
  { label: 'Resource Pool', value: CloudconfigClusterType.SHARED_POOL },
  {
    label: 'Premium & BYOC',
    value: CloudconfigClusterType.LOGICAL_CLUSTER
  },
  { label: 'Dedicated', value: CloudconfigClusterType.DEDICATED_TIDB },
  { label: 'TiCDC NG', value: CloudconfigClusterType.TICDC_NG },
  { label: 'Changefeed NG', value: CloudconfigClusterType.CHANGEFEED_NG },
  { label: 'TiCDC', value: CloudconfigClusterType.TICDC },
  { label: 'Changefeed', value: CloudconfigClusterType.CHANGEFEED }
]

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

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

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

const getDefaultTemplateRowId = (
  record: CloudconfigTemplateDefaultCaseBinding,
  rowIndex: number
) =>
  [
    record.template_id,
    record.default_case?.version,
    record.default_case?.cloud_provider,
    record.default_case?.region,
    record.default_case?.instance_type,
    record.default_case?.config_type,
    record.default_case?.tenant_id,
    record.cluster_type,
    rowIndex
  ].join('|')

const buildInitialFilters = (
  defaultClusterType: CloudconfigClusterType,
  defaultTenantId?: string,
  exactMatch?: boolean
): DefaultTemplateFilters => ({
  cluster_type:
    defaultClusterType as CloudConfigControllerListTemplateDefaultCaseBindingsClusterType,
  config_type_is: undefined,
  default_for_cloud_provider: undefined,
  default_for_instance_type: undefined,
  default_for_tenant_id: defaultTenantId,
  default_for_version: undefined,
  exact_match: exactMatch
})

const isDedicatedClusterType = (
  clusterType: DefaultTemplateFilters['cluster_type']
) => clusterType === CloudconfigClusterType.DEDICATED_TIDB

const isTiCDCClusterType = (
  clusterType: DefaultTemplateFilters['cluster_type']
) => clusterType === CloudconfigClusterType.TICDC

const isTiCDCNgClusterType = (
  clusterType: DefaultTemplateFilters['cluster_type']
) => clusterType === CloudconfigClusterType.TICDC_NG

const shouldShowVersionFilter = (
  clusterType: DefaultTemplateFilters['cluster_type']
) => isDedicatedClusterType(clusterType) || isTiCDCClusterType(clusterType)

const shouldShowFullTemplateColumns = (
  clusterType: DefaultTemplateFilters['cluster_type']
) => isDedicatedClusterType(clusterType) || isTiCDCClusterType(clusterType)

const shouldShowConfigTypeFilter = (
  clusterType: DefaultTemplateFilters['cluster_type']
) => !isTiCDCClusterType(clusterType) && !isTiCDCNgClusterType(clusterType)

const sanitizeFilters = (
  filters: DefaultTemplateFilters
): DefaultTemplateFilters => ({
  ...filters,
  config_type_is: shouldShowConfigTypeFilter(filters.cluster_type)
    ? filters.config_type_is
    : undefined,
  default_for_instance_type: isDedicatedClusterType(filters.cluster_type)
    ? filters.default_for_instance_type
    : undefined,
  default_for_version: shouldShowVersionFilter(filters.cluster_type)
    ? filters.default_for_version
    : undefined
})

export default function DefaultTemplateTable({
  default_cluster_type,
  default_tenant_id,
  exact_match,
  deletable,
  hidden_filters,
  tool_bar_extra
}: {
  default_cluster_type: CloudconfigClusterType
  default_tenant_id?: string
  exact_match?: boolean
  deletable?: boolean
  hidden_filters?: DefaultTemplateHiddenFilter[]
  tool_bar_extra?: React.ReactNode[]
}) {
  const [versionOpts, setVersionOpts] = useState<string[]>([])
  const [configTypeOpts, setConfigTypeOpts] = useState<string[]>([])
  const [uniqueInstanceOpts, setUniqueInstanceOpts] = useState<
    CloudconfigCloudInstanceType[]
  >([])
  const [filters, setFilters] = useState<DefaultTemplateFilters>(() =>
    buildInitialFilters(default_cluster_type, default_tenant_id, exact_match)
  )
  const [appliedFilters, setAppliedFilters] = useState<DefaultTemplateFilters>(
    () =>
      buildInitialFilters(default_cluster_type, default_tenant_id, exact_match)
  )
  const [dataSource, setDataSource] = useState<
    CloudconfigTemplateDefaultCaseBinding[]
  >([])
  const [loading, setLoading] = useState(false)
  const [pagination, setPagination] = useState<TablePaginationState>({
    pageIndex: 0,
    pageSize: DEFAULT_TEMPLATE_PAGE_SIZE
  })
  const [total, setTotal] = useState(0)
  const [reloadKey, setReloadKey] = useState(0)
  const [viewTemplate, setViewTemplate] =
    useState<CloudconfigTemplateDefaultCaseBinding>()
  const [delTemplate, setDelTemplate] =
    useState<CloudconfigTemplateDefaultCaseBinding>()
  const [deleting, setDeleting] = useState(false)

  useEffect(() => {
    const nextFilters = buildInitialFilters(
      default_cluster_type,
      default_tenant_id,
      exact_match
    )
    setFilters(nextFilters)
    setAppliedFilters(nextFilters)
    setPagination((current) => ({ ...current, pageIndex: 0 }))
  }, [default_cluster_type, default_tenant_id, exact_match])

  const loadBindings = useCallback(async () => {
    setLoading(true)
    try {
      const response =
        await cloudConfigControllerListTemplateDefaultCaseBindings({
          ...appliedFilters,
          page: pagination.pageIndex + 1,
          per_page: pagination.pageSize
        })

      setDataSource(response.data.items || [])
      setTotal(response.data.total || 0)
    } catch (error) {
      notifier.error(getErrorContent(error), {
        title: 'Failed to load default templates'
      })
    } finally {
      setLoading(false)
    }
  }, [appliedFilters, pagination.pageIndex, pagination.pageSize])

  useEffect(() => {
    void loadBindings()
  }, [loadBindings, reloadKey])

  useEffect(() => {
    let mounted = true

    async function fetchOptions() {
      try {
        const configTypes = shouldShowConfigTypeFilter(filters.cluster_type)
          ? await cloudConfigControllerListConfigTypes(filters.cluster_type)
          : undefined
        const versions = shouldShowVersionFilter(filters.cluster_type)
          ? await cloudConfigControllerListAvailableClusterVersions(
              CloudconfigClusterType.DEDICATED_TIDB
            )
          : undefined

        if (!mounted) {
          return
        }

        setVersionOpts(
          versions?.data.items?.map((version) => version.version!) || []
        )
        setConfigTypeOpts(configTypes?.data.config_types || [])
      } catch (error) {
        notifier.error(getErrorContent(error), {
          title: 'Failed to load filter options'
        })
      }
    }

    void fetchOptions()

    return () => {
      mounted = false
    }
  }, [filters.cluster_type])

  useEffect(() => {
    let mounted = true

    async function fetchUniqueInstance() {
      if (!isDedicatedClusterType(filters.cluster_type)) {
        setUniqueInstanceOpts([])
        return
      }

      try {
        const params: CloudConfigControllerListInstanceTypesParams = {
          config_type: filters.config_type_is,
          version: filters.default_for_version
        }
        const tuples = (
          await cloudConfigControllerListInstanceTypes(
            filters.cluster_type,
            params
          )
        ).data

        if (!mounted) {
          return
        }

        setUniqueInstanceOpts(tuples.instance_types || [])
      } catch (error) {
        notifier.error(getErrorContent(error), {
          title: 'Failed to load instance types'
        })
      }
    }

    void fetchUniqueInstance()

    return () => {
      mounted = false
    }
  }, [
    filters.cluster_type,
    filters.config_type_is,
    filters.default_for_version
  ])

  const instanceTypeOptions = useMemo(
    () =>
      uniqueInstanceOpts
        .filter(
          (instanceType) =>
            !filters.default_for_cloud_provider ||
            filters.default_for_cloud_provider === instanceType.cloud_provider
        )
        .map((instanceType) => ({
          label: `[${instanceType.cloud_provider}] ${instanceType.instance_type}`,
          value: instanceType.instance_type || ''
        })),
    [filters.default_for_cloud_provider, uniqueInstanceOpts]
  )

  const handleSearch = useCallback(() => {
    setAppliedFilters(sanitizeFilters(filters))
    setPagination((current) => ({ ...current, pageIndex: 0 }))
    setReloadKey((current) => current + 1)
  }, [filters])

  const handleReset = useCallback(() => {
    const nextFilters = buildInitialFilters(
      default_cluster_type,
      default_tenant_id,
      exact_match
    )
    setFilters(nextFilters)
    setAppliedFilters(nextFilters)
    setPagination((current) => ({ ...current, pageIndex: 0 }))
    setReloadKey((current) => current + 1)
  }, [default_cluster_type, default_tenant_id, exact_match])

  const handleDeleteTemplateBinding = useCallback(async () => {
    if (!delTemplate) {
      return
    }

    setDeleting(true)
    try {
      const response =
        await cloudConfigControllerDeleteTemplateDefaultCaseBindingByOp({
          default_case_bindings: delTemplate,
          reason: 'Delete from Default Template Binding Table'
        })

      const operationId = response.data.instance_id
      notifier.success(
        operationId ? (
          <>
            Request submitted successfully. Click{' '}
            <a
              href={`/operations/${operationId}`}
              target="_blank"
              rel="noreferrer"
            >
              operation detail
            </a>{' '}
            to check progress.
          </>
        ) : (
          'Request submitted successfully.'
        ),
        { title: 'Default template binding delete submitted' }
      )
      setDelTemplate(undefined)
      setReloadKey((current) => current + 1)
    } catch (error) {
      notifier.error(getErrorContent(error), {
        title: 'Failed to delete template binding'
      })
    } finally {
      setDeleting(false)
    }
  }, [delTemplate])

  const columnsTemplate = useMemo<
    MRT_ColumnDef<CloudconfigTemplateDefaultCaseBinding>[]
  >(() => {
    const showFullTableColumns = shouldShowFullTemplateColumns(
      filters.cluster_type
    )
    const columns: MRT_ColumnDef<CloudconfigTemplateDefaultCaseBinding>[] = [
      {
        accessorFn: (record) => record.default_case?.version || 'Any',
        header: 'Version',
        id: 'version',
        size: 120
      },
      {
        accessorFn: (record) => record.default_case?.config_type || '-',
        header: 'Config Type',
        id: 'config_type',
        size: 130
      },
      {
        accessorFn: (record) => record.default_case?.region || 'Any',
        header: 'Region',
        id: 'region',
        size: 150
      },
      ...(showFullTableColumns
        ? [
            {
              accessorFn: (record: CloudconfigTemplateDefaultCaseBinding) =>
                record.default_case?.cloud_provider || 'Any',
              header: 'Cloud Provider',
              id: 'cloud_provider',
              size: 150
            },
            {
              accessorFn: (record: CloudconfigTemplateDefaultCaseBinding) =>
                record.default_case?.instance_type || 'Any',
              header: 'Instance Type',
              id: 'instance_type',
              size: 180
            }
          ]
        : []),
      {
        accessorFn: (record) => record.default_case?.tenant_id || 'Any',
        header: 'Tenant ID',
        id: 'tenant_id',
        size: 180
      },
      {
        accessorFn: (record) => record.template_id || '-',
        header: 'Default Template',
        id: 'template_id',
        size: 140
      },
      {
        Cell: ({ row }) => {
          const record = row.original

          return (
            <Group gap={8} wrap="nowrap">
              <Button
                size="sm"
                variant="subtle"
                onClick={() => {
                  setViewTemplate(record)
                }}
              >
                View
              </Button>
              <Button
                component={Link}
                size="sm"
                target="_blank"
                to={`/template/${record.template_id}?cluster_type=${record.cluster_type}`}
                rel="noreferrer"
                variant="subtle"
              >
                Detail
              </Button>
              {deletable && (
                <Button
                  color="red"
                  size="sm"
                  variant="subtle"
                  onClick={() => {
                    setDelTemplate(record)
                  }}
                >
                  Delete
                </Button>
              )}
            </Group>
          )
        },
        header: 'Actions',
        id: 'actions',
        size: 190
      }
    ]

    return columns
  }, [deletable, filters.cluster_type])

  const showVersionFilter = shouldShowVersionFilter(filters.cluster_type)
  const showConfigTypeFilter = shouldShowConfigTypeFilter(filters.cluster_type)
  const showInstanceTypeFilter = isDedicatedClusterType(filters.cluster_type)
  const hideClusterTypeFilter = hidden_filters?.includes('cluster_type')
  const hideTenantIdFilter = hidden_filters?.includes('tenant_id')
  const filterColumnCount =
    (hideClusterTypeFilter ? 0 : 1) +
    (showVersionFilter ? 1 : 0) +
    (showConfigTypeFilter ? 1 : 0) +
    (showInstanceTypeFilter ? 1 : 0) +
    (hideTenantIdFilter ? 0 : 1)

  return (
    <Stack gap="md">
      <Card withBorder shadow="xs" padding="md" radius="sm">
        <Stack gap="md">
          <Stack gap="sm">
            {filterColumnCount > 0 && (
              <SimpleGrid
                cols={{ base: 1, sm: 2, lg: filterColumnCount }}
                spacing="sm"
              >
                {!hideClusterTypeFilter && (
                  <Select
                    data={CLUSTER_TYPE_OPTIONS}
                    label="Cluster Type"
                    value={filters.cluster_type}
                    onChange={(value) => {
                      if (!value) {
                        return
                      }
                      setFilters((current) => ({
                        ...current,
                        cluster_type:
                          value as CloudConfigControllerListTemplateDefaultCaseBindingsClusterType,
                        config_type_is: undefined,
                        default_for_instance_type: undefined,
                        default_for_version: undefined
                      }))
                    }}
                  />
                )}
                {showVersionFilter && (
                  <Select
                    clearable
                    data={versionOpts.map((version) => ({
                      label: version,
                      value: version
                    }))}
                    label="Version"
                    searchable
                    value={filters.default_for_version || null}
                    onChange={(value) => {
                      setFilters((current) => ({
                        ...current,
                        default_for_instance_type: undefined,
                        default_for_version: value || undefined
                      }))
                    }}
                  />
                )}
                {showConfigTypeFilter && (
                  <Select
                    clearable
                    data={configTypeOpts.map((configType) => ({
                      label: configType,
                      value: configType
                    }))}
                    label="Config Type"
                    searchable
                    value={filters.config_type_is || null}
                    onChange={(value) => {
                      setFilters((current) => ({
                        ...current,
                        config_type_is: value || undefined,
                        default_for_instance_type: undefined
                      }))
                    }}
                  />
                )}
                {showInstanceTypeFilter && (
                  <Select
                    clearable
                    data={instanceTypeOptions}
                    label="Instance Type"
                    searchable
                    value={filters.default_for_instance_type || null}
                    onChange={(value) => {
                      setFilters((current) => ({
                        ...current,
                        default_for_instance_type: value || undefined
                      }))
                    }}
                  />
                )}
                {!hideTenantIdFilter && (
                  <TextInput
                    label="Tenant ID"
                    placeholder="Any tenant"
                    value={filters.default_for_tenant_id || ''}
                    onChange={(event) => {
                      setFilters((current) => ({
                        ...current,
                        default_for_tenant_id: event.target.value || undefined
                      }))
                    }}
                    onKeyDown={(event) => {
                      if (event.key === 'Enter') {
                        handleSearch()
                      }
                    }}
                  />
                )}
              </SimpleGrid>
            )}

            <Group justify="flex-end" gap="sm" wrap="wrap">
              <Button
                leftSection={<IconSearchLg size={16} />}
                onClick={handleSearch}
              >
                Search
              </Button>
              <Button variant="default" onClick={handleReset}>
                Reset
              </Button>
              <Tooltip label="Reload">
                <ActionIcon
                  aria-label="Reload default templates"
                  loading={loading}
                  variant="default"
                  onClick={() => setReloadKey((current) => current + 1)}
                >
                  <IconRefreshCcw01 size={16} />
                </ActionIcon>
              </Tooltip>
              {tool_bar_extra}
            </Group>
          </Stack>

          <ProTable<CloudconfigTemplateDefaultCaseBinding>
            key={filters.cluster_type}
            columns={columnsTemplate}
            data={dataSource}
            enableColumnActions={false}
            enableColumnFilters={false}
            enableDensityToggle={false}
            enableFullScreenToggle={false}
            enableHiding={false}
            enablePagination={total > DEFAULT_TEMPLATE_PAGE_SIZE}
            enableSorting={false}
            enableTopToolbar={false}
            getRowId={(row, rowIndex) => getDefaultTemplateRowId(row, rowIndex)}
            loading={loading}
            manualPagination
            onPaginationChange={(updaterOrValue) => {
              setPagination((currentPagination) =>
                getFixedPagination(
                  updaterOrValue as TablePaginationUpdater,
                  currentPagination
                )
              )
            }}
            pagination={{ showRowsPerPage: false }}
            rowCount={total}
            state={{ pagination }}
          />
        </Stack>
      </Card>

      <Modal
        title={
          <Typography
            variant="title-lg"
            style={{ fontSize: 16, lineHeight: '24px' }}
          >
            View Template
          </Typography>
        }
        opened={viewTemplate !== undefined}
        onClose={() => {
          setViewTemplate(undefined)
        }}
        size="80vw"
      >
        {viewTemplate ? (
          <TemplateView
            template_id={viewTemplate.template_id?.toString()!}
            cluster_type={viewTemplate.cluster_type!}
            with_default_cases={false}
          />
        ) : (
          <Typography variant="body-lg" c="carbon.6">
            No template selected.
          </Typography>
        )}
      </Modal>

      <Modal
        title="Delete default template binding"
        opened={delTemplate !== undefined}
        onClose={() => {
          if (!deleting) {
            setDelTemplate(undefined)
          }
        }}
        centered
      >
        <Stack gap="md">
          <Typography variant="body-sm">
            Confirm to delete this default template binding?
          </Typography>
          <Group justify="flex-end">
            <Button
              variant="default"
              disabled={deleting}
              onClick={() => setDelTemplate(undefined)}
            >
              Cancel
            </Button>
            <Button
              color="red"
              loading={deleting}
              onClick={handleDeleteTemplateBinding}
            >
              Confirm
            </Button>
          </Group>
        </Stack>
      </Modal>
    </Stack>
  )
}
