import { useMemo, useState } from 'react';
import {
  Alert,
  Badge,
  Button,
  Card,
  Container,
  Group,
  Loader,
  Select,
  Stack,
  Table,
  Text,
  TextInput,
  ThemeIcon,
} from '@mantine/core';
import { IconAlertTriangle, IconFingerprint, IconScan, IconSearch, IconX } from '@tabler/icons-react';
import { useDebouncedValue } from '@mantine/hooks';
import {
  extractErrorMessage,
  useEnrollBiometricMutation,
  useGenerateBsidMutation,
  useGetBiometricEnrollmentsQuery,
  useGetBiometricSimulateCapabilitiesQuery,
  useListSeafarerRegistrationsQuery,
  useRevokeBiometricEnrollmentMutation,
  type BiometricModality,
  type SeafarerRegistration,
} from '@ema-platform/api';
import { notify, PageHeader, StatusBadge } from '@ema-platform/ui';
import { useDateDisplayer } from '@ema-platform/shared';

const MODALITIES: { value: BiometricModality; label: string }[] = [
  { value: 'FINGERPRINT', label: 'Fingerprint' },
  { value: 'FACE', label: 'Face' },
];

function applicantName(r: Pick<SeafarerRegistration, 'firstName' | 'middleName' | 'lastName'>): string {
  return [r.firstName, r.middleName, r.lastName].filter(Boolean).join(' ') || '—';
}

/**
 * No scanner is wired yet (US-BIO placeholder): "Simulate Scan" stands in for
 * the real vendor SDK capture, producing a random template so the rest of the
 * pipeline — encrypt, store, print — is exercisable end to end. Swap the
 * simulated bytes for the SDK's real template once a vendor is chosen; the
 * API call shape (base64 template + format tag) does not change.
 */
function fakeTemplate(): string {
  const bytes = crypto.getRandomValues(new Uint8Array(64));
  return btoa(String.fromCharCode(...bytes));
}

/**
 * Pick a seafarer waiting on enrolment.
 *
 * AWAITING_BIOMETRICS only: enrolment is the step that unblocks the review, so
 * this queue is exactly the registrations held for it. An approved seafarer has
 * already been through here — listing them would invite a second capture of
 * someone who is finished.
 */
function ProfilePicker({ onPick }: { onPick: (r: SeafarerRegistration) => void }) {
  const [search, setSearch] = useState('');
  const [debounced] = useDebouncedValue(search, 300);
  const { data, isFetching } = useListSeafarerRegistrationsQuery({
    status: 'AWAITING_BIOMETRICS',
    search: debounced || undefined,
    take: 10,
  });

  return (
    <Card withBorder radius="md" p="md">
      <TextInput
        placeholder="Search seafarers awaiting enrolment…"
        leftSection={<IconSearch size={14} />}
        value={search}
        onChange={(e) => setSearch(e.currentTarget.value)}
        mb="sm"
      />
      {isFetching && <Loader size="sm" />}
      <Table highlightOnHover fz="sm">
        <Table.Tbody>
          {(data?.items ?? []).map((r) => (
            <Table.Tr key={r.id} onClick={() => onPick(r)} style={{ cursor: 'pointer' }}>
              <Table.Td>
                <Text fz="sm" fw={600}>{applicantName(r)}</Text>
                {/* Not seafarerNumber: that is only issued on approval, which
                    is downstream of this screen, so it is always blank here. */}
                <Text fz="xs" c="dimmed" ff="monospace">{r.registrationNumber}</Text>
              </Table.Td>
            </Table.Tr>
          ))}
          {!isFetching && (data?.items ?? []).length === 0 && (
            <Table.Tr>
              <Table.Td>
                <Text fz="sm" c="dimmed">No seafarer is waiting on enrolment.</Text>
              </Table.Td>
            </Table.Tr>
          )}
        </Table.Tbody>
      </Table>
    </Card>
  );
}

/** Backoffice counter screen: enroll a scanner capture against a profile, view what's on file, print the slip. */
export function BiometricEnrollmentPage() {
  const showDate = useDateDisplayer();
  const [selected, setSelected] = useState<SeafarerRegistration | null>(null);
  const [modality, setModality] = useState<BiometricModality>('FINGERPRINT');
  const [deviceId, setDeviceId] = useState('');

  const profileId = selected?.profileId ?? '';
  const { data: enrollments, isLoading } = useGetBiometricEnrollmentsQuery(profileId, { skip: !profileId });
  // No vendor SDK integrated yet — "Simulate Scan" fakes a capture so the
  // rest of the flow is exercisable. Reports false in production unless
  // ALLOW_BIOMETRIC_SIMULATION=true, same shortcut the payment bypass uses.
  const { data: capabilities } = useGetBiometricSimulateCapabilitiesQuery();
  const simulateEnabled = capabilities?.simulateEnabled ?? false;
  const [generateBsid, { isLoading: generatingBsid }] = useGenerateBsidMutation();
  // Seeded from the seafarer registration list (which does not carry BSID
  // yet) and updated locally once generated — this screen's only source of
  // truth for it until the registry surfaces the profile's BSID directly.
  const [bsid, setBsid] = useState<string | null>(null);
  const [enroll, { isLoading: enrolling }] = useEnrollBiometricMutation();
  const [revoke, { isLoading: revoking }] = useRevokeBiometricEnrollmentMutation();

  const hasActive = useMemo(
    () => (m: BiometricModality) => (enrollments ?? []).some((e) => e.modality === m),
    [enrollments],
  );

  async function handleEnroll() {
    if (!profileId) return;
    try {
      await enroll({
        profileId,
        modality,
        template: fakeTemplate(),
        templateFormat: 'SIMULATED',
        deviceId: deviceId || undefined,
        consentAt: new Date().toISOString(),
      }).unwrap();
      notify.success(`${modality === 'FINGERPRINT' ? 'Fingerprint' : 'Face'} enrolled.`);
    } catch (err) {
      notify.error(extractErrorMessage(err, 'Enrollment failed.'));
    }
  }

  async function handleGenerateBsid() {
    if (!profileId) return;
    try {
      const result = await generateBsid(profileId).unwrap();
      setBsid(result.bsid);
      notify.success(`BSID ${result.bsid} generated.`);
    } catch (err) {
      notify.error(extractErrorMessage(err, 'Could not generate BSID.'));
    }
  }

  async function handleRevoke(id: string) {
    if (!profileId) return;
    try {
      await revoke({ id, profileId, reason: 'Withdrawn at counter' }).unwrap();
      notify.success('Enrollment revoked.');
    } catch (err) {
      notify.error(extractErrorMessage(err, 'Could not revoke.'));
    }
  }

  return (
    <Container size="md" py="md">
      <PageHeader
        title="Biometric Enrollment"
        subtitle="Capture a fingerprint or face template for a seafarer awaiting enrolment, then issue their BSID."
      />

      {!selected ? (
        <ProfilePicker
          onPick={(r) => {
            setSelected(r);
            setBsid(null);
          }}
        />
      ) : (
        <Stack gap="md">
          <Card withBorder radius="md" p="md">
            <Group justify="space-between">
              <div>
                <Text fw={600}>{applicantName(selected)}</Text>
                <Text fz="xs" c="dimmed" ff="monospace">{selected.registrationNumber}</Text>
              </div>
              <Button
                variant="subtle"
                size="xs"
                leftSection={<IconX size={14} />}
                onClick={() => {
                  setSelected(null);
                  setBsid(null);
                }}
              >
                Change seafarer
              </Button>
            </Group>
          </Card>

          <Card withBorder radius="md" p="md">
            <Text fz="sm" fw={600} mb="sm">Capture</Text>
            {simulateEnabled ? (
              <>
                <Alert color="yellow" icon={<IconAlertTriangle size={16} />} mb="sm" variant="light">
                  No scanner is wired yet — this simulates a capture so the rest of the flow can be tested.
                </Alert>
                <Group align="flex-end">
                  <Select label="Modality" data={MODALITIES} value={modality} onChange={(v) => setModality((v as BiometricModality) ?? 'FINGERPRINT')} w={160} />
                  <TextInput label="Device (optional)" placeholder="scanner-01" value={deviceId} onChange={(e) => setDeviceId(e.currentTarget.value)} w={180} />
                  <Button leftSection={<IconScan size={16} />} onClick={handleEnroll} loading={enrolling}>
                    Simulate Scan &amp; Enroll
                  </Button>
                </Group>
              </>
            ) : (
              <Alert color="gray" icon={<IconAlertTriangle size={16} />} variant="light">
                No scanner is wired yet, and capture simulation is off in this environment.
              </Alert>
            )}
          </Card>

          <Card withBorder radius="md" p="md">
            <Text fz="sm" fw={600} mb="sm">Biometric Subject ID (BSID)</Text>
            <Text fz="xs" c="dimmed" mb="sm">
              Required before this registration can be approved. Generating it is final —
              confirm the capture is good first.
            </Text>
            <Group justify="space-between">
              {bsid ? (
                <StatusBadge tone="success" label={`BSID ${bsid}`} />
              ) : (
                <Badge color="gray" variant="light">Not generated</Badge>
              )}
              {!bsid && (
                <Button
                  size="xs"
                  onClick={handleGenerateBsid}
                  loading={generatingBsid}
                  disabled={!hasActive('FINGERPRINT') && !hasActive('FACE')}
                >
                  Generate BSID
                </Button>
              )}
            </Group>
          </Card>

          <Card withBorder radius="md" p="md">
            <Text fz="sm" fw={600} mb="sm">On file</Text>
            {isLoading ? (
              <Loader size="sm" />
            ) : (
              <Stack gap="xs">
                {MODALITIES.map((m) => (
                  <Group key={m.value} justify="space-between" p="xs" style={{ borderRadius: 8, background: 'var(--mantine-color-default-hover)' }}>
                    <Group gap="xs">
                      <ThemeIcon variant="light" color={hasActive(m.value) ? 'teal' : 'gray'} size={30} radius="md">
                        <IconFingerprint size={15} />
                      </ThemeIcon>
                      <Text fz="sm">{m.label}</Text>
                    </Group>
                    {hasActive(m.value) ? (
                      <Group gap="xs">
                        <StatusBadge tone="success" label="Enrolled" />
                        <Button
                          size="xs"
                          color="red"
                          variant="subtle"
                          loading={revoking}
                          onClick={() => {
                            const row = (enrollments ?? []).find((e) => e.modality === m.value);
                            if (row) handleRevoke(row.id);
                          }}
                        >
                          Revoke
                        </Button>
                      </Group>
                    ) : (
                      <Badge color="gray" variant="light">Not enrolled</Badge>
                    )}
                  </Group>
                ))}
                {(enrollments ?? []).map((e) => (
                  <Text key={e.id} fz="xs" c="dimmed">
                    {e.modality} captured {showDate(e.enrolledAt)}{e.deviceId ? ` · ${e.deviceId}` : ''}
                  </Text>
                ))}
              </Stack>
            )}
          </Card>
        </Stack>
      )}
    </Container>
  );
}

export default BiometricEnrollmentPage;
