import { notifier } from '@tidbcloud/uikit'
import { Box, Group, Typography, Button, Accordion, Popover, Flex } from '@tidbcloud/uikit'
import { Form, FormTextInput } from '@tidbcloud/uikit/biz'
import { MRT_ColumnDef, ProTable } from '@tidbcloud/uikit/biz'
import DOMPurify from 'dompurify'
import { startCase } from 'lodash-es'
import React, { useCallback, useEffect, useState } from 'react'
import { Controller, useForm, useFormContext, useWatch } from 'react-hook-form'

import config from 'config'
import { FilterMultiSelect } from 'dbaas/screens/ClusterV2/features/Diagnosis/SQLRepository/List/FilterMultiSelect'
import type { CentralAuditLogAccessRecord } from 'dbaas/services'
import {
  clusterServiceGetAuditLogAccessRecords,
  clusterServiceDeleteAuditLogAccessRecord,
  clusterServiceCreateAuditLogAccessRecord
} from 'dbaas/services'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'

const AccessTypes = [
  'AlterTable',
  'AnalyzeTable',
  'Begin',
  'Change',
  'Commit',
  'CreateDatabase',
  'CreateIndex',
  'CreateTable',
  'CreateView',
  'CreateUser',
  'Delete',
  'DropDatabase',
  'DropIndex',
  'DropView',
  'DropTable',
  'DescTable',
  'ExplainAnalyzeSQL',
  'ExplainSQL',
  'Replace',
  'Insert',
  'LoadData',
  'RollBack',
  'Select',
  'Set',
  'Show',
  'TruncateTable',
  'Update',
  'Grant',
  'Revoke',
  'Deallocate',
  'Execute',
  'Prepare',
  'Use',
  'CreateBinding',
  'IndexAdvise',
  'DropBinding',
  'Trace',
  'Shutdown',
  'other'
]

const DeleteRecord: React.FC<
  React.PropsWithChildren<{
    clusterId: string
    recordId: string
    onDelete: () => void
    onCancel?: () => void
  }>
> = ({ clusterId, recordId, onDelete, onCancel }) => {
  const {
    store: { activeProjectId, tenantData }
  } = useStores()
  const [loading, setLoading] = useState(false)
  const onConfirm = () => {
    if (loading) {
      return
    }
    setLoading(true)
    clusterServiceDeleteAuditLogAccessRecord(tenantData.id, activeProjectId, clusterId, recordId, {
      timeout: config.AUDIT_LOG_TIMEOUT
    })
      .then(() => {
        setLoading(false)
        onDelete()
      })
      .catch((e) => {
        setLoading(false)
        notifier.error(<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(getErrorMessage(e, true)) }} />)
      })
  }
  return (
    <Popover onClose={onCancel} width={180} withArrow>
      <Popover.Target>
        <Button color="red" variant="light" size="xs" data-mp-event="mp-delete-1691461015782">
          Delete
        </Button>
      </Popover.Target>
      <Popover.Dropdown>
        <Typography variant="title-md" mb={8}>
          Delete this record?
        </Typography>
        <Flex justify="flex-end">
          <Button
            loading={loading}
            type="button"
            color="red"
            variant="light"
            size="xs"
            onClick={onConfirm}
            data-mp-event="mp-confirm-1691461015785"
          >
            Confirm
          </Button>
        </Flex>
      </Popover.Dropdown>
    </Popover>
  )
}

const AccessTypeSelect: React.FC<React.PropsWithChildren<{}>> = () => {
  const { control, setValue } = useFormContext<{ access_type_list: string[] }>()
  const type = useWatch({
    control,
    name: 'access_type_list',
    defaultValue: []
  })
  const options = [{ label: 'All', value: '*' }].concat(
    AccessTypes.map((t) => {
      return {
        label: startCase(t),
        value: t,
        disabled: type.length === 1 && type[0] === '*'
      }
    })
  )
  useEffect(() => {
    if (type.length !== 1 && type.includes('*')) {
      setValue('access_type_list', ['*'])
    }
  }, [type, setValue])
  return (
    <Controller
      name="access_type_list"
      control={control}
      rules={{
        validate: (value) => {
          if (!value.length) {
            return 'Required'
          }
          return true
        }
      }}
      render={({ field }) => {
        const { value, onChange, ...restField } = field
        return (
          <FilterMultiSelect
            // w={280}
            // clearable
            // label="Access Type"
            // placeholder="select"
            // searchable={true}
            value={value}
            kind="access_type_list"
            data={options}
            // withAsterisk
            // styles={{ label: { marginBottom: 6, lineHeight: '20px' }, wrapper: { marginBottom: 3 } }}
            onChange={onChange}
            {...restField}
          />
        )
      }}
    />
  )
}

export const AccessTable: React.FC<React.PropsWithChildren<{ clusterId: string }>> = ({ clusterId }) => {
  const {
    store: { activeProjectId, tenantData }
  } = useStores()
  const [data, setData] = useState<CentralAuditLogAccessRecord[]>([])
  const [fetching, setFetching] = useState(false)
  const form = useForm<CentralAuditLogAccessRecord>({
    reValidateMode: 'onChange',
    defaultValues: {
      access_type_list: [],
      db_expr: '',
      user_expr: '',
      table_expr: ''
    }
  })

  const onSubmit = async (data: CentralAuditLogAccessRecord) => {
    if (data.access_type_list.length === 1 && data.access_type_list[0] === '*') {
      data.access_type_list = [...AccessTypes]
    }
    await clusterServiceCreateAuditLogAccessRecord(
      tenantData.id,
      activeProjectId,
      clusterId,
      {
        org_id: tenantData.id,
        project_id: activeProjectId,
        cluster_id: clusterId,
        record: data
      },
      {
        timeout: config.AUDIT_LOG_TIMEOUT
      }
    )
    form.reset()
    fetcher()
  }

  const fetcher = useCallback(() => {
    setFetching(true)
    clusterServiceGetAuditLogAccessRecords(tenantData.id, activeProjectId, clusterId, {
      timeout: config.AUDIT_LOG_TIMEOUT
    })
      .then((data) => {
        setData(data.records || [])
        setFetching(false)
      })
      .catch((_e) => {
        setFetching(false)
      })
  }, [tenantData.id, activeProjectId, setData, clusterId])

  const columns: MRT_ColumnDef<CentralAuditLogAccessRecord>[] = [
    {
      header: 'User Expr',
      accessorKey: 'user_expr'
    },
    {
      header: 'DB Expr',
      accessorKey: 'db_expr'
    },
    {
      header: 'Table Expr',
      accessorKey: 'table_expr'
    },
    {
      header: 'Access Type',
      minSize: 200,
      accessorFn: ({ access_type_list = [] }) => {
        if (!access_type_list.length) {
          return '-'
        }
        return (
          <Accordion
            chevronPosition="left"
            defaultValue=""
            styles={{
              item: { border: 'none' },
              control: {
                padding: 8,
                paddingLeft: 0,
                '&:hover': { backgroundColor: 'transparent' }
              },
              chevron: { marginLeft: -6 }
            }}
          >
            <Accordion.Item value="total">
              <Accordion.Control>
                <Typography variant="body-lg">Total: {access_type_list.length}</Typography>
              </Accordion.Control>
              <Accordion.Panel>
                {access_type_list.map((type, index) => (
                  <Typography variant="body-lg" key={type + index.toString()} sx={{ textIndent: '1rem' }}>
                    {index + 1}. {startCase(type)}
                  </Typography>
                ))}
              </Accordion.Panel>
            </Accordion.Item>
          </Accordion>
        )
      }
    },
    {
      header: 'Actions',
      size: 100,
      accessorFn: (row) => {
        return <DeleteRecord key={row.id} recordId={row.id} clusterId={clusterId} onDelete={fetcher} />
      }
    }
  ]

  useEffect(() => {
    fetcher()
  }, [fetcher])

  return (
    <Box>
      <Form<CentralAuditLogAccessRecord>
        form={{
          ...form,
          handleSubmit: (...args) => {
            const fn = form.handleSubmit(...args)
            return (e: React.BaseSyntheticEvent) => {
              e.stopPropagation()
              e.preventDefault()
              return fn()
            }
          }
        }}
        onSubmit={onSubmit}
        actionsProps={{ confirmText: 'Add' }}
        mb={16}
      >
        <div>
          <Typography variant="title-md">Filter Rules</Typography>
          <Button
            component="a"
            display="inline-block"
            h="auto"
            p={0}
            sx={{ alignSelf: 'flex-start' }}
            variant="subtle"
            href="https://docs.pingcap.com/tidbcloud/tidb-cloud-auditing#specify-auditing-filter-rules"
            target="_blank"
            rel="noreferrer"
            data-mp-event="Learn How To Set Up Filter Rules Link Clicked"
          >
            Learn how to set up filter rules
          </Button>
        </div>
        <Group justify="space-between" grow gap={8} align="flex-start">
          <FormTextInput name="user_expr" label="User Expr" withAsterisk rules={{ required: 'Required' }} />
          <FormTextInput name="db_expr" label="DB Expr" withAsterisk rules={{ required: 'Required' }} />
          <FormTextInput name="table_expr" label="Table Expr" withAsterisk rules={{ required: 'Required' }} />
          <AccessTypeSelect />
        </Group>
      </Form>
      <ProTable
        loading={fetching}
        columns={columns}
        data={data}
        emptyMessage="No Data"
        mantinePaperProps={{ mx: 24 }}
      />
    </Box>
  )
}
