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 { useFieldArray, useFormContext } from 'react-hook-form'

import { DataFormat, DataFormatDisplayName } from 'dbaas/features/Import'
import { LightningFileNamingExample } from 'dbaas/features/Import/LightningFileNamingExample'
import CSVConfiguration from 'dbaas/screens/DataImportV2/CSVConfiguration'
import {
  CSVFormat,
  ImportFileTypeEnum,
  ImportTargetTableInfo
} from 'dbaas/services/api-clients/legacy/serverless/interface'

import { autoDetectDataFormat } from './helper'

export type ConfigureMappingFormData = {
  use_tidb_dumpling_naming_conventions: boolean
  data_format: ImportFileTypeEnum | 'UNKNOWN'
  csv_format: CSVFormat
  target_table_infos: ImportTargetTableInfo[]
}

export const ConfigureMapping = ({
  onCancel,
  onGoPrev,
  onFinish
}: {
  onCancel: () => void
  onGoPrev: () => void
  onFinish: (data: any) => void
}) => {
  const methods = useFormContext()
  const followNamingConventions = methods.watch('use_tidb_dumpling_naming_conventions')
  const dataFormat = methods.watch('data_format') as ImportFileTypeEnum
  const csvFormat = methods.watch('csv_format')
  const isSingleFile = methods.watch('is_single_file')
  const sourceUri = methods.watch('source_uri')

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

  const onConfirmCSVChange = (csvFormat: CSVFormat) => {
    methods.setValue('csv_format', csvFormat)
  }

  const onSubmit = (data: ConfigureMappingFormData) => {
    // auto detect data format if using custom mapping
    if (!data.use_tidb_dumpling_naming_conventions) {
      const targetTableInfos = data.target_table_infos.filter(
        (i) => !!i.target_table?.database && !!i.target_table.table && !!i.custom_file
      )
      const dataFormat = autoDetectDataFormat(targetTableInfos)
      methods.setValue('data_format', dataFormat)
    }

    onFinish(data)
  }

  return (
    <Card p={24}>
      <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>{sourceUri}</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 ? (
          <>
            <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={[
                    {
                      label: DataFormatDisplayName[DataFormat.csv],
                      value: ImportFileTypeEnum.CSV
                    },
                    {
                      label: DataFormatDisplayName[DataFormat.parquet],
                      value: ImportFileTypeEnum.PARQUET
                    },
                    {
                      label: DataFormatDisplayName[DataFormat.aurora],
                      value: ImportFileTypeEnum.AURORA_SNAPSHOT
                    },
                    {
                      label: DataFormatDisplayName[DataFormat.sql_file],
                      value: ImportFileTypeEnum.SQL
                    }
                  ]}
                />

                {dataFormat === ImportFileTypeEnum.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</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) => {
                  return (
                    <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.database`}
                        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({
                              target_table: {
                                database: '',
                                table: ''
                              },
                              custom_file: ''
                            })
                          }
                        >
                          <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>
  )
}
