import {
  ActionIcon,
  Alert,
  Box,
  Button,
  Card,
  Code,
  Divider,
  Group,
  HoverCard,
  Popover,
  Stack,
  Typography
} from '@tidbcloud/uikit'
import { FormCheckbox, FormRadioGroup, FormTextInput } from '@tidbcloud/uikit/biz'
import { IconInfoCircle, IconPlus, IconTrash01 } from '@tidbcloud/uikit/icons'
import { useMemoizedFn } from 'ahooks'
import { useFieldArray, useFormContext } from 'react-hook-form'

import { SharedCluster } from 'dbaas/features/ClusterManagement/cluster'
import { LightningFileNamingExample } from 'dbaas/features/Import/LightningFileNamingExample'
import { DataFormat, getFormatOptions } from 'dbaas/screens/DataImportV2/constant'
import CSVConfiguration from 'dbaas/screens/DataImportV2/CSVConfiguration'

import { autoDetectDataFormat, defaultMappingRow, normalizeCustomMappings } from './helper'
import type { ImportFromCloudDedicatedFormData } from './types'

export const ConfigureMapping = ({
  cluster,
  onCancel,
  onGoPrev,
  onFinish
}: {
  cluster: SharedCluster
  onCancel: () => void
  onGoPrev: () => void
  onFinish: () => void
}) => {
  const methods = useFormContext<ImportFromCloudDedicatedFormData>()
  const followNamingConventions = methods.watch('use_tidb_dumpling_naming_conventions')
  const dataFormat = methods.watch('data_format')
  const csvFormat = methods.watch('csv_format')
  const sourceUrl = methods.watch('source_url')
  const sourceType = methods.watch('data_source_type')
  const isSingleFile = methods.watch('is_single_file')
  const formatOptions = getFormatOptions(cluster.provider, sourceType, isSingleFile ? 'single' : 'multiple').filter(
    (item) => !item.disabled
  )

  const { fields, append, remove } = useFieldArray({
    control: methods.control,
    name: 'target_table_infos'
  })

  const onConfirmCSVChange = useMemoizedFn((nextCsvFormat: ImportFromCloudDedicatedFormData['csv_format']) => {
    methods.setValue('csv_format', nextCsvFormat)
  })

  const onSubmit = useMemoizedFn((data: ImportFromCloudDedicatedFormData) => {
    if (!data.use_tidb_dumpling_naming_conventions) {
      const normalizedMappings = normalizeCustomMappings(data)
      methods.setValue('target_table_infos', normalizedMappings.length > 0 ? normalizedMappings : [defaultMappingRow()])
      methods.setValue('data_format', autoDetectDataFormat(normalizedMappings))
    }

    onFinish()
  })

  return (
    <Card p={24} data-testid="import-from-cloud-dedicated-step2">
      <Stack component="form" onSubmit={methods.handleSubmit(onSubmit)}>
        <Typography variant="title-lg">Destination Mapping</Typography>

        {!isSingleFile && (
          <FormCheckbox
            name="use_tidb_dumpling_naming_conventions"
            label={
              <Typography>
                Use{' '}
                <a
                  href="https://docs.pingcap.com/tidbcloud/naming-conventions-for-data-import/"
                  target="_blank"
                  rel="noreferrer"
                >
                  TiDB file naming conventions
                </a>{' '}
                for automatic mapping.
              </Typography>
            }
          />
        )}

        {isSingleFile && (
          <Alert color="peacock" icon={<IconInfoCircle />} sx={{ wordBreak: 'break-all' }}>
            You specified a single file URI: <strong>{sourceUrl}</strong>
            <br />
            So you only need to enter the target database and table name below.
            <br />
            Please ensure that the target database and table already exist and are empty before proceeding.
          </Alert>
        )}

        {followNamingConventions && !isSingleFile ? (
          <>
            <Card>
              <Card.Section bg="carbon.2" p={16}>
                <Typography c="carbon.7">Source</Typography>
              </Card.Section>
              <Card.Section>
                <Divider />
              </Card.Section>
              <Card.Section p={16} component={Stack}>
                <Typography>
                  All files that are named after <LightningFileNamingExample dataFormat={dataFormat} /> and match the
                  selected data format will be used as data source.
                </Typography>

                <FormRadioGroup
                  label="Data Format"
                  name="data_format"
                  data={formatOptions.map((item) => ({
                    label: item.title,
                    value: item.value + ''
                  }))}
                />

                {Number(dataFormat) === DataFormat.csv && (
                  <Box>
                    <Popover withArrow withinPortal shadow="md">
                      <Popover.Target>
                        <Button type="button" variant="default" size="xs">
                          Edit CSV Configuration
                        </Button>
                      </Popover.Target>
                      <Popover.Dropdown>
                        <CSVConfiguration defaultValue={csvFormat} onChange={onConfirmCSVChange} />
                      </Popover.Dropdown>
                    </Popover>
                  </Box>
                )}
              </Card.Section>
            </Card>

            <Card>
              <Card.Section bg="carbon.2" p={16}>
                <Typography c="carbon.7">Destination</Typography>
              </Card.Section>
              <Card.Section>
                <Divider />
              </Card.Section>
              <Card.Section p={16} component={Stack} gap={16}>
                <Typography>
                  Data will be imported into databases and tables following the naming pattern from your source files:{' '}
                  <Code>
                    {'${'}db_name{'}'}.{'${'}table_name{'}'}
                  </Code>
                </Typography>

                <Typography>
                  If no corresponding databases or tables are found, the following schema files in your source will be
                  executed to create them:
                </Typography>

                <Box bg="carbon.1" p={12} style={{ borderRadius: 6 }}>
                  <Stack gap={4}>
                    <Group gap={8} align="flex-start">
                      <Typography c="carbon.7" variant="body-sm" style={{ minWidth: 80 }}>
                        Databases:
                      </Typography>
                      <Typography c="carbon.8" ff="mono" variant="body-sm">
                        {'${'}db_name{'}'}-schema-create.sql
                      </Typography>
                    </Group>
                    <Group gap={8} align="flex-start">
                      <Typography c="carbon.7" variant="body-sm" style={{ minWidth: 80 }}>
                        Tables:
                      </Typography>
                      <Typography c="carbon.8" ff="mono" variant="body-sm">
                        {'${'}db_name{'}'}.{'${'}table_name{'}'}-schema.sql
                      </Typography>
                    </Group>
                  </Stack>
                </Box>
              </Card.Section>
            </Card>
          </>
        ) : (
          <>
            <Card>
              <Card.Section bg="carbon.2" p={16}>
                <Group gap={8} wrap="nowrap">
                  <Typography c="carbon.7" sx={{ flex: 1 }}>
                    <Group gap={8} wrap="nowrap">
                      <span>Source Pattern</span>
                      <HoverCard>
                        <HoverCard.Target>
                          <IconInfoCircle />
                        </HoverCard.Target>
                        <HoverCard.Dropdown maw={400} fz="13px">
                          Specify the source file pattern as a relative path from your source URI.
                          <br />
                          <br />
                          Wildcards are supported:
                          <br />
                          <strong>?</strong> - matches one character
                          <br />
                          <strong>*</strong> - matches multiple characters
                          <br />
                          <br />
                          For example:
                          <br />• my-data.csv - matches my-data.csv
                          <br />• my-data?.csv - matches my-data1.csv, my-data2.csv, etc.
                          <br />• my-data*.csv - matches all CSV files starting with my-data
                        </HoverCard.Dropdown>
                      </HoverCard>
                    </Group>
                  </Typography>
                  <Typography c="carbon.7" sx={{ flexBasis: 150 }}>
                    Target Database
                  </Typography>
                  <Typography c="carbon.7" sx={{ flexBasis: 150 }}>
                    Target Table
                  </Typography>
                  <Box w={26} />
                </Group>
              </Card.Section>
              <Card.Section>
                <Divider />
              </Card.Section>
              <Card.Section p={16} component={Stack}>
                {fields.map((field, index) => (
                  <Group key={field.id} gap={8} wrap="nowrap" align="flex-start">
                    <FormTextInput
                      name={`target_table_infos.${index}.custom_file`}
                      size="xs"
                      sx={{ flex: 1 }}
                      placeholder="Enter source file pattern"
                      disabled={isSingleFile}
                      rules={{ required: true }}
                    />
                    <FormTextInput
                      name={`target_table_infos.${index}.target_table.schema`}
                      size="xs"
                      placeholder="Enter database name"
                      sx={{ flexBasis: 150 }}
                      rules={{ required: true }}
                    />
                    <FormTextInput
                      name={`target_table_infos.${index}.target_table.table`}
                      size="xs"
                      placeholder="Enter table name"
                      sx={{ flexBasis: 150 }}
                      rules={{ required: true }}
                    />

                    {index === 0 ? (
                      <ActionIcon
                        variant="default"
                        sx={{ visibility: isSingleFile ? 'hidden' : 'visible' }}
                        onClick={() => append(defaultMappingRow())}
                      >
                        <IconPlus />
                      </ActionIcon>
                    ) : (
                      <ActionIcon variant="default" onClick={() => remove(index)}>
                        <IconTrash01 />
                      </ActionIcon>
                    )}
                  </Group>
                ))}
              </Card.Section>
            </Card>

            <Typography variant="body-md" c="carbon.7" mt={-8}>
              If your source files are in the CSV format, you can{' '}
              <Popover withArrow withinPortal shadow="md">
                <Popover.Target>
                  <a href="#">edit CSV configuration here.</a>
                </Popover.Target>
                <Popover.Dropdown>
                  <CSVConfiguration defaultValue={csvFormat} onChange={onConfirmCSVChange} />
                </Popover.Dropdown>
              </Popover>
            </Typography>
          </>
        )}

        <Divider mx={-24} />

        <Group justify="flex-end">
          <Button variant="default" onClick={onCancel}>
            Cancel
          </Button>
          <Button variant="default" onClick={onGoPrev}>
            Previous
          </Button>
          <Button type="submit">Next</Button>
        </Group>
      </Stack>
    </Card>
  )
}
