import {
  Badge,
  Box,
  Button,
  Code,
  Group,
  Stack,
  Switch,
  TextInput,
  Typography
} from '@tidbcloud/uikit'
import {
  MRT_ColumnDef,
  MRT_ExpandedState,
  ProTable
} from '@tidbcloud/uikit/biz'
import {
  IconCheck,
  IconFileSearch02,
  IconSearchLg
} from '@tidbcloud/uikit/icons'
import { AxiosResponse } from 'axios'
import { useEffect, useState } from 'react'
import { Link } from 'react-router-dom'

import { CloudconfigConfigurationChange } from 'apiClient/services/devops/interface'
import { toLocal } from 'pages/Devops/Maintenance/Detail'
import { GetResp } from 'pages/Tenants/ClusterDetail/Configs/CurrentConfig/Current'

import ExpandTable from './ExpandTable'

export interface ConfigHistoriesParam {
  [key: string]: any
}

export type ConfigHistoriesController = (
  params: unknown,
  options?: unknown
) => Promise<AxiosResponse<GetResp>>

const PAGE_SIZE = 10

type TablePaginationState = {
  pageIndex: number
  pageSize: number
}

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

const phaseColorMap: Record<string, string> = {
  applied: 'green',
  applying: 'blue',
  approving: 'yellow',
  cancelled: 'gray',
  created: 'gray',
  failed: 'red',
  wait_for_apply: 'cyan',
  withdrawn: 'red'
}

const tableHeadCellProps = {
  sx: {
    backgroundColor: 'var(--mantine-color-carbon-1, #f1f3f5)',
    color: 'var(--mantine-color-carbon-7, #495057)',
    fontWeight: 600,
    padding: '12px 14px !important'
  }
}

const tableBodyCellProps = {
  sx: {
    padding: '12px 14px !important',
    verticalAlign: 'top'
  }
}

const getChangeRowId = (change: CloudconfigConfigurationChange) =>
  String(change.id)

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

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

const hasVersionChange = (change?: CloudconfigConfigurationChange) => {
  const version = change?.scope?.version
  const hasBaseVersionChange =
    version != null && (version.from !== undefined || version.to !== undefined)
  const hasComponentImageChange = change?.scope?.components?.some(
    (component) => {
      const imageTag = component.modified_image_tag

      return (
        imageTag != null &&
        (imageTag.from !== undefined || imageTag.to !== undefined)
      )
    }
  )

  return Boolean(hasBaseVersionChange || hasComponentImageChange)
}

const ConfigHistories = ({
  changesAPI,
  changesParams
}: {
  changesAPI: ConfigHistoriesController
  changesParams: ConfigHistoriesParam
}) => {
  const [changes, setChanges] = useState<CloudconfigConfigurationChange[]>()
  const [total, setTotal] = useState(0)
  const [loading, setLoading] = useState(false)
  const [pagination, setPagination] = useState<TablePaginationState>({
    pageIndex: 0,
    pageSize: PAGE_SIZE
  })
  const [searchQuery, setSearchQeury] = useState<string>()
  const [appliedSearchQuery, setAppliedSearchQuery] = useState<string>()
  const [expanded, setExpanded] = useState<MRT_ExpandedState>({})
  const hasExpandedRows =
    expanded === true || Object.values(expanded).some(Boolean)
  const shouldPaginate = total > PAGE_SIZE
  const changesParamsKey = JSON.stringify(changesParams)

  useEffect(() => {
    fetch()
  }, [
    appliedSearchQuery,
    pagination.pageIndex,
    pagination.pageSize,
    changesParamsKey
  ])

  async function fetch(
    nextPagination = pagination,
    nextSearchQuery = appliedSearchQuery
  ) {
    setLoading(true)
    try {
      const resp = (
        await changesAPI({
          ...changesParams,
          have_modified_param_like: nextSearchQuery,
          page: nextPagination.pageIndex + 1,
          per_page: nextPagination.pageSize
        })
      ).data
      const nextChanges = resp.items || []
      setExpanded({})
      setChanges(nextChanges)
      setTotal(resp.total ?? nextChanges.length)
    } catch (e) {
      console.error(e)
    } finally {
      setLoading(false)
    }
  }

  const handleSearch = () => {
    const nextPagination = {
      pageIndex: 0,
      pageSize: PAGE_SIZE
    }
    const nextSearchQuery = searchQuery

    if (
      appliedSearchQuery === nextSearchQuery &&
      pagination.pageIndex === nextPagination.pageIndex &&
      pagination.pageSize === nextPagination.pageSize
    ) {
      fetch(nextPagination, nextSearchQuery)
      return
    }

    setAppliedSearchQuery(nextSearchQuery)
    setPagination(nextPagination)
  }

  const columns: MRT_ColumnDef<CloudconfigConfigurationChange>[] = [
    {
      header: 'ID',
      accessorKey: 'id',
      size: 80,
      Cell: ({ row }) =>
        row.original.id ? <Code>{row.original.id}</Code> : undefined
    },
    {
      header: 'Applicant',
      accessorKey: 'applicant',
      size: 180
    },
    {
      header: 'Phase',
      accessorKey: 'phase',
      size: 105,
      Cell: ({ row }) =>
        row.original.phase ? (
          <Badge
            color={phaseColorMap[row.original.phase] || 'gray'}
            variant="dot"
            size="lg"
            sx={{ paddingLeft: 0 }}
          >
            {row.original.phase}
          </Badge>
        ) : (
          '-'
        )
    },
    {
      header: 'Version Change',
      id: 'version-change',
      size: 140,
      Cell: ({ row }) =>
        hasVersionChange(row.original) ? (
          <Badge
            color="green"
            leftSection={<IconCheck size={12} />}
            size="md"
            variant="light"
            sx={{
              background: 'var(--mantine-color-green-0, #e6fcf5)',
              border: '1px solid var(--mantine-color-green-3, #8ce99a)',
              color: 'var(--mantine-color-green-8, #2b8a3e)',
              fontWeight: 600,
              letterSpacing: 0,
              textTransform: 'none'
            }}
          >
            yes
          </Badge>
        ) : (
          <Typography variant="body-sm" c="carbon.5">
            -
          </Typography>
        )
    },
    {
      header: 'Time',
      accessorKey: 'created_at',
      accessorFn: (record) => toLocal(record.created_at),
      size: 160
    },
    {
      header: 'Action',
      id: 'action',
      size: 110,
      Cell: ({ row }) => (
        <Button
          component={Link}
          leftSection={<IconFileSearch02 size={16} />}
          size="xs"
          to={`/confighistories/${row.original.id}`}
          variant="subtle"
        >
          Detail
        </Button>
      )
    }
  ]

  return (
    <Box>
      <Group
        justify="space-between"
        mb="md"
        pb="md"
        style={{
          borderBottom: '1px solid var(--mantine-color-carbon-2, #e9ecef)'
        }}
      >
        <Stack gap={2}>
          <Typography variant="headline-sm">
            Config Modification Histories
          </Typography>
          <Typography variant="body-sm" c="carbon.6">
            Review version, component image tag, and file parameter changes.
          </Typography>
        </Stack>
        <Group gap="sm" wrap="nowrap">
          <TextInput
            leftSection={<IconSearchLg size={16} />}
            miw={360}
            value={searchQuery}
            onChange={(v) => {
              setSearchQeury(v.target.value)
            }}
            placeholder="search by param name"
          />
          <Button
            leftSection={<IconSearchLg size={16} />}
            onClick={handleSearch}
          >
            Search
          </Button>
          <Switch
            checked={hasExpandedRows}
            disabled={!changes?.length}
            label="Expand all"
            onChange={(event) => {
              setExpanded(event.currentTarget.checked ? true : {})
            }}
          />
        </Group>
      </Group>
      <ProTable
        columns={columns}
        data={changes || []}
        displayColumnDefOptions={{
          'mrt-row-expand': {
            size: 48
          }
        }}
        emptyMessage="No config modification histories"
        enableExpandAll={false}
        enableExpanding
        enablePagination={shouldPaginate}
        getRowId={getChangeRowId}
        loading={loading}
        manualPagination
        mantinePaperProps={{
          shadow: 'none',
          style: {
            border: '1px solid var(--mantine-color-carbon-2, #e9ecef)',
            borderRadius: 8,
            overflow: 'hidden'
          }
        }}
        mantineTableProps={{
          sx: {
            tableLayout: 'fixed',
            width: '100%'
          }
        }}
        mantineTableBodyCellProps={tableBodyCellProps}
        mantineTableHeadCellProps={tableHeadCellProps}
        onPaginationChange={(updaterOrValue) => {
          setPagination((currentPagination) =>
            getFixedPagination(
              updaterOrValue as TablePaginationUpdater,
              currentPagination
            )
          )
        }}
        pagination={shouldPaginate ? { showTotal: true } : undefined}
        renderDetailPanel={({ row }) => <ExpandTable change={row.original} />}
        rowCount={shouldPaginate ? total : undefined}
        state={{
          expanded,
          pagination
        }}
        onExpandedChange={(updater) => {
          setExpanded((previous) =>
            typeof updater === 'function' ? updater(previous) : updater
          )
        }}
      />
    </Box>
  )
}

export default ConfigHistories
