import { useEffect, useState } from 'react';
import {
  Alert,
  Badge,
  Button,
  Card,
  Center,
  Code,
  Group,
  Loader,
  Modal,
  NumberInput,
  Select,
  Stack,
  Switch,
  Table,
  Text,
  TextInput,
  Title,
} from '@mantine/core';
import { useForm } from '@mantine/form';
import { useDisclosure } from '@mantine/hooks';
import { IconInfoCircle, IconPlus } from '@tabler/icons-react';
import { useTranslation } from 'react-i18next';
import { ModalFooter, notify, useErrorHandler } from '@ema-platform/ui';
import {
  useCreateNumberFormatMutation,
  useGetNumberFormatsQuery,
  usePreviewNumberFormatMutation,
  useUpdateNumberFormatMutation,
} from '../api/configuration-api';
import type {
  NumberFormatPayload,
  NumberFormatScope,
} from '../types/configuration';

const SCOPES: { value: NumberFormatScope; label: string }[] = [
  { value: 'SEAFARER_NUMBER', label: 'Seafarer Number' },
  { value: 'SEAMAN_BOOK_NUMBER', label: 'Seaman Book Number' },
  { value: 'BTC_NUMBER', label: 'BTC Number' },
  { value: 'BSID', label: 'Biometric Subject ID (BSID)' },
];

const scopeLabel = (scope: NumberFormatScope) =>
  SCOPES.find((s) => s.value === scope)?.label ?? scope;

/**
 * Backoffice control over the shape of generated identifiers.
 *
 * Authoring a format supersedes the one it replaces rather than editing it:
 * numbers already issued were produced by a specific format, and the register
 * has to stay explicable. Superseded rows therefore stay listed.
 */
export function NumberFormatTab() {
  const { t } = useTranslation();
  const { handleError } = useErrorHandler();
  const [opened, { open, close }] = useDisclosure(false);
  const [sample, setSample] = useState<string | null>(null);

  const { data: formats = [], isLoading } = useGetNumberFormatsQuery();
  const [createFormat, { isLoading: creating }] = useCreateNumberFormatMutation();
  const [updateFormat] = useUpdateNumberFormatMutation();
  const [previewFormat] = usePreviewNumberFormatMutation();

  const form = useForm<NumberFormatPayload>({
    initialValues: {
      scope: 'SEAFARER_NUMBER',
      prefix: 'SEA',
      includeYear: true,
      separator: '-',
      sequenceLength: 6,
      startingNumber: 1,
      isActive: true,
    },
    validate: {
      prefix: (value) => (value.trim() ? null : t('numberFormat.prefixRequired', 'Prefix is required')),
      sequenceLength: (value) =>
        value && value >= 1 && value <= 12
          ? null
          : t('numberFormat.lengthRange', 'Length must be between 1 and 12'),
      startingNumber: (value) =>
        value && value >= 1
          ? null
          : t('numberFormat.startPositive', 'Starting number must be at least 1'),
    },
  });

  // The sample comes from the server so it cannot drift from what an approval
  // will actually generate. Debounced because it follows every keystroke.
  const { values } = form;
  useEffect(() => {
    if (!values.prefix?.trim()) {
      setSample(null);
      return;
    }
    const timer = setTimeout(() => {
      previewFormat(values)
        .unwrap()
        .then((result) => setSample(result.sample))
        // A preview that fails is not worth interrupting authoring for; the
        // create call reports properly if the format is genuinely invalid.
        .catch(() => setSample(null));
    }, 300);
    return () => clearTimeout(timer);
  }, [values, previewFormat]);

  const submit = form.onSubmit(async (payload) => {
    try {
      await createFormat(payload).unwrap();
      notify.success(
        t('numberFormat.created', 'Number format saved. It applies to numbers issued from now on.'),
      );
      close();
      form.reset();
    } catch (error) {
      handleError(error);
    }
  });

  const retire = async (id: string) => {
    try {
      await updateFormat({ id, isActive: false }).unwrap();
      notify.success(t('numberFormat.retired', 'Format retired.'));
    } catch (error) {
      handleError(error);
    }
  };

  if (isLoading) {
    return (
      <Center h={200}>
        <Loader />
      </Center>
    );
  }

  return (
    <Stack gap="md">
      <Group justify="space-between">
        <div>
          <Title order={4}>{t('numberFormat.title', 'Number Formats')}</Title>
          <Text fz="sm" c="dimmed">
            {t(
              'numberFormat.subtitle',
              'The shape of generated seafarer, seaman book and certificate numbers.',
            )}
          </Text>
        </div>
        <Button leftSection={<IconPlus size={16} />} onClick={open} size="sm">
          {t('numberFormat.add', 'New Format')}
        </Button>
      </Group>

      <Alert icon={<IconInfoCircle size={16} />} color="blue" variant="light">
        {t(
          'numberFormat.notice',
          'Changing a format never alters numbers already issued. A new format applies only to numbers generated after it becomes active.',
        )}
      </Alert>

      {formats.length === 0 ? (
        <Card withBorder radius="md" p="lg">
          <Text fz="sm" c="dimmed" ta="center">
            {t(
              'numberFormat.empty',
              'No formats configured. Numbers use the built-in default until one is added.',
            )}
          </Text>
        </Card>
      ) : (
        <Table.ScrollContainer minWidth={720}>
          <Table striped highlightOnHover>
            <Table.Thead>
              <Table.Tr>
                <Table.Th>{t('numberFormat.scope', 'Identifier')}</Table.Th>
                <Table.Th>{t('numberFormat.example', 'Example')}</Table.Th>
                <Table.Th>{t('numberFormat.sequence', 'Sequence')}</Table.Th>
                <Table.Th>{t('numberFormat.status', 'Status')}</Table.Th>
                <Table.Th />
              </Table.Tr>
            </Table.Thead>
            <Table.Tbody>
              {formats.map((format) => {
                const parts = [format.prefix];
                if (format.includeYear) parts.push(String(new Date().getFullYear()));
                parts.push(String(format.startingNumber).padStart(format.sequenceLength, '0'));
                return (
                  <Table.Tr key={format.id}>
                    <Table.Td>{scopeLabel(format.scope)}</Table.Td>
                    <Table.Td>
                      <Code>{parts.join(format.separator)}</Code>
                    </Table.Td>
                    <Table.Td>{format.sequenceLength} digits</Table.Td>
                    <Table.Td>
                      <Badge color={format.isActive ? 'green' : 'gray'} variant="light">
                        {format.isActive
                          ? t('numberFormat.active', 'Active')
                          : t('numberFormat.superseded', 'Superseded')}
                      </Badge>
                    </Table.Td>
                    <Table.Td>
                      {format.isActive && (
                        <Button
                          variant="subtle"
                          color="red"
                          size="compact-sm"
                          onClick={() => retire(format.id)}
                        >
                          {t('numberFormat.retire', 'Retire')}
                        </Button>
                      )}
                    </Table.Td>
                  </Table.Tr>
                );
              })}
            </Table.Tbody>
          </Table>
        </Table.ScrollContainer>
      )}

      <Modal
        opened={opened}
        onClose={close}
        title={t('numberFormat.add', 'New Format')}
        size="md"
      >
        <form onSubmit={submit}>
          <Stack gap="sm">
            <Select
              label={t('numberFormat.scope', 'Identifier')}
              data={SCOPES}
              allowDeselect={false}
              {...form.getInputProps('scope')}
            />
            <TextInput
              label={t('numberFormat.prefix', 'Prefix')}
              placeholder="SEA"
              maxLength={12}
              {...form.getInputProps('prefix')}
            />
            <Switch
              label={t('numberFormat.includeYear', 'Include the issuing year')}
              {...form.getInputProps('includeYear', { type: 'checkbox' })}
            />
            <TextInput
              label={t('numberFormat.separator', 'Separator')}
              maxLength={4}
              {...form.getInputProps('separator')}
            />
            <NumberInput
              label={t('numberFormat.sequenceLength', 'Sequence length')}
              description={t('numberFormat.sequenceHelp', 'Zero-padded width, e.g. 6 gives 000001.')}
              min={1}
              max={12}
              {...form.getInputProps('sequenceLength')}
            />
            <NumberInput
              label={t('numberFormat.startingNumber', 'Starting number')}
              description={t(
                'numberFormat.startHelp',
                'Where the counter begins. Raising it later does not renumber anything already issued.',
              )}
              min={1}
              {...form.getInputProps('startingNumber')}
            />

            {sample && (
              <Alert color="gray" variant="light">
                <Group gap="xs">
                  <Text fz="sm">{t('numberFormat.next', 'Next number will look like')}</Text>
                  <Code>{sample}</Code>
                </Group>
              </Alert>
            )}

            <ModalFooter>
              <Button variant="default" onClick={close} size="sm">
                {t('configuration.cancel', 'Cancel')}
              </Button>
              <Button type="submit" loading={creating} size="sm">
                {t('numberFormat.save', 'Save Format')}
              </Button>
            </ModalFooter>
          </Stack>
        </form>
      </Modal>
    </Stack>
  );
}
