import { useRef, useState } from 'react';
import { Alert, Badge, Button, Card, FileButton, Group, Loader, Stack, Text } from '@mantine/core';
import { IconAlertTriangle, IconCheck, IconFileUpload } from '@tabler/icons-react';
import {
  conditionHolds,
  uploadDocument,
  useLocalized,
  type Attachment,
  type DocumentRequirement,
} from '@ema-platform/api';

const MAX_FILE_SIZE_BYTES = 5 * 1024 * 1024;

/** A configured requirement, with whether this applicant must supply it. */
export type RegistrationSlot = DocumentRequirement & { isRequired: boolean };

/**
 * The document slots a registration asks for.
 *
 * Configuration, not a constant: these are `document_requirements` rows
 * against the SEAFARER_REGISTRATION licence type, the same ones the backoffice
 * edits and the server validates against. A conditional requirement — the
 * passport copy, wanted once a passport number is declared — is evaluated
 * against the answers under `identity`, exactly as the server does it, so the
 * wizard and the submit check can never disagree about what is being asked
 * for.
 */
export function documentSlots(
  requirements: DocumentRequirement[],
  answers: Record<string, unknown>,
): RegistrationSlot[] {
  const context = { identity: answers, personal: answers } as Record<
    string,
    Record<string, unknown>
  >;
  return requirements
    .filter(
      (requirement) =>
        requirement.mode !== 'CONDITIONAL' ||
        conditionHolds(requirement.conditionExpression, context),
    )
    .map((requirement) => ({
      ...requirement,
      isRequired:
        requirement.mode === 'ALWAYS' ||
        (requirement.mode === 'CONDITIONAL' &&
          conditionHolds(requirement.conditionExpression, context)),
    }));
}

export function RegistrationDocuments({
  registrationId,
  requirements,
  answers,
  attachments,
  readOnly,
  onUploaded,
}: {
  registrationId: string;
  requirements: DocumentRequirement[];
  /** The registration's answers, for evaluating conditional requirements. */
  answers: Record<string, unknown>;
  attachments: Attachment[];
  readOnly?: boolean;
  onUploaded: () => void;
}) {
  const localized = useLocalized();
  const [busy, setBusy] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const resetRefs = useRef<Record<string, () => void>>({});

  async function handle(documentKey: string, file: File | null) {
    if (!file) return;
    if (file.size > MAX_FILE_SIZE_BYTES) {
      setError(`File exceeds 5MB limit (${(file.size / 1024 / 1024).toFixed(1)}MB).`);
      resetRefs.current[documentKey]?.();
      return;
    }
    setBusy(documentKey);
    setError(null);
    const result = await uploadDocument({
      ownerType: 'SEAFARER_REGISTRATION',
      ownerId: registrationId,
      documentKey,
      file,
    });
    setBusy(null);
    resetRefs.current[documentKey]?.();
    if (result.ok) onUploaded();
    else setError(result.error);
  }

  return (
    <Stack gap="sm">
      {error && (
        <Alert color="red" icon={<IconAlertTriangle size={16} />}>
          {error}
        </Alert>
      )}
      {documentSlots(requirements, answers).map((slot) => {
        const existing = attachments.find((a) => a.documentKey === slot.key);
        const uploaded = Boolean(existing?.files?.length);
        const fromVault = Boolean(existing?.copiedFromAttachmentId);
        return (
          <Card
            key={slot.key}
            withBorder
            padding="md"
            style={{
              borderColor: uploaded ? 'var(--mantine-color-teal-4)' : undefined,
              borderStyle: uploaded ? 'solid' : 'dashed',
            }}
          >
            <Group justify="space-between" wrap="nowrap" align="flex-start">
              <div style={{ minWidth: 0 }}>
                <Group gap="xs">
                  <Text fw={600} size="sm">
                    {localized(slot.name)}
                  </Text>
                  {!slot.isRequired && (
                    <Badge size="xs" variant="light" color="gray">
                      optional
                    </Badge>
                  )}
                  {uploaded && (
                    <Badge size="xs" color="teal" leftSection={<IconCheck size={10} />}>
                      uploaded
                    </Badge>
                  )}
                  {/* Copied from My Documents rather than uploaded here. */}
                  {fromVault && (
                    <Badge size="xs" variant="light" color="blue">
                      from My Documents
                    </Badge>
                  )}
                </Group>
                {slot.description && (
                  <Text size="xs" c="dimmed" mt={2}>
                    {localized(slot.description)}
                  </Text>
                )}
                {existing?.files?.[0] && (
                  <Text size="xs" c="dimmed" truncate mt={2}>
                    {existing.files[0].originalName} · {(existing.files[0].sizeBytes / 1024).toFixed(0)} KB
                  </Text>
                )}
              </div>
              <Group gap="xs" wrap="nowrap">
                {existing?.files?.[0]?.url && (
                  <Button size="xs" variant="subtle" component="a" href={existing.files[0].url} target="_blank">
                    View
                  </Button>
                )}
                {!readOnly && (
                  <FileButton
                    resetRef={(r) => {
                      if (r) resetRefs.current[slot.key] = r;
                    }}
                    onChange={(file) => handle(slot.key, file)}
                    accept={slot.allowedMimeTypes?.join(',')}
                  >
                    {(props) => (
                      <Button
                        {...props}
                        size="xs"
                        variant={uploaded ? 'light' : 'filled'}
                        leftSection={busy === slot.key ? <Loader size={12} /> : <IconFileUpload size={14} />}
                        disabled={busy === slot.key}
                      >
                        {uploaded ? 'Replace' : 'Upload'}
                      </Button>
                    )}
                  </FileButton>
                )}
              </Group>
            </Group>
          </Card>
        );
      })}
    </Stack>
  );
}
