import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
  Alert,
  Badge,
  Button,
  Group,
  Modal,
  Paper,
  Select,
  Stack,
  Table,
  Text,
  Textarea,
  Title,
} from '@mantine/core';
import { IconInfoCircle, IconUserCheck } from '@tabler/icons-react';
import { notify } from '@ema-platform/ui';
import { extractErrorMessage } from '@ema-platform/api';
import {
  useGetExamRegistrationsQuery,
  useRecordAttendanceMutation,
} from '../api/exam-api';
import type { AttendanceStatus, ExamRegistration } from '../types/exam';

const ATTENDANCE_COLOR: Record<AttendanceStatus, string> = {
  REGISTERED: 'gray',
  PRESENT: 'teal',
  LATE: 'yellow',
  ABSENT: 'red',
  WITHDRAWN: 'orange',
  DISQUALIFIED: 'red',
};

/** Rulings that end the sitting, and so must be explained (US-EXAM-009). */
const NEEDS_REMARK: AttendanceStatus[] = ['WITHDRAWN', 'DISQUALIFIED'];

const OPTIONS: AttendanceStatus[] = [
  'PRESENT',
  'LATE',
  'ABSENT',
  'WITHDRAWN',
  'DISQUALIFIED',
];

/**
 * The invigilator's register for one session (US-EXAM-009).
 *
 * Marking a paper later depends on what is recorded here: an absent,
 * withdrawn or disqualified candidate has no result to enter.
 */
export function ExamCandidatesPanel({ examId }: { examId: string }) {
  const { t } = useTranslation();
  const { data: registrations, isError } = useGetExamRegistrationsQuery(examId);
  const [recordAttendance, { isLoading }] = useRecordAttendanceMutation();
  const [target, setTarget] = useState<ExamRegistration | null>(null);
  const [status, setStatus] = useState<AttendanceStatus>('PRESENT');
  const [remark, setRemark] = useState('');

  const candidateName = (registration: ExamRegistration) =>
    [
      registration.profile?.firstName,
      registration.profile?.middleName,
      registration.profile?.lastName,
    ]
      .filter(Boolean)
      .join(' ') || registration.profileId.slice(0, 8);

  const save = async () => {
    if (!target) return;
    if (NEEDS_REMARK.includes(status) && !remark.trim()) {
      notify.error(t('exam.candidates.remarkRequired'));
      return;
    }
    try {
      await recordAttendance({
        registrationId: target.id,
        status,
        remark: remark.trim() || undefined,
      }).unwrap();
      notify.success(t('exam.candidates.recorded'));
      setTarget(null);
      setRemark('');
    } catch (error) {
      notify.error(extractErrorMessage(error, t('exam.incidents.error')));
    }
  };

  // Officers without the invigilation permission simply do not see the
  // register; the endpoint refuses them and there is nothing to show.
  if (isError) return null;

  return (
    <Paper withBorder radius="lg" p="lg">
      <Title order={5} mb="md">
        {t('exam.candidates.section')}
      </Title>
      {(registrations ?? []).length === 0 ? (
        <Alert color="gray" icon={<IconInfoCircle size={16} />}>
          {t('exam.candidates.none')}
        </Alert>
      ) : (
        <Table striped highlightOnHover>
          <Table.Thead>
            <Table.Tr>
              <Table.Th>{t('exam.candidates.admission')}</Table.Th>
              <Table.Th>{t('exam.candidates.name')}</Table.Th>
              <Table.Th>{t('exam.candidates.attempt')}</Table.Th>
              <Table.Th>{t('exam.candidates.attendance')}</Table.Th>
              <Table.Th>{t('exam.candidates.remark')}</Table.Th>
              <Table.Th />
            </Table.Tr>
          </Table.Thead>
          <Table.Tbody>
            {(registrations ?? []).map((registration) => (
              <Table.Tr key={registration.id}>
                <Table.Td>
                  <Text fz="sm" ff="monospace" fw={600}>
                    {registration.admissionNumber}
                  </Text>
                </Table.Td>
                <Table.Td>
                  <Text fz="sm">{candidateName(registration)}</Text>
                </Table.Td>
                <Table.Td>
                  <Badge
                    size="sm"
                    variant="light"
                    color={registration.kind === 'RETAKE' ? 'orange' : 'blue'}
                  >
                    {registration.kind === 'RETAKE'
                      ? t('exam.candidates.retake', { n: registration.attemptNumber })
                      : t('exam.candidates.firstSitting')}
                  </Badge>
                </Table.Td>
                <Table.Td>
                  <Badge
                    size="sm"
                    variant="light"
                    color={ATTENDANCE_COLOR[registration.attendanceStatus] ?? 'gray'}
                  >
                    {t(`exam.attendance.${registration.attendanceStatus}`)}
                  </Badge>
                </Table.Td>
                <Table.Td>
                  <Text fz="xs" c="dimmed" maw={220} lineClamp={2}>
                    {registration.attendanceRemark ?? '—'}
                  </Text>
                </Table.Td>
                <Table.Td>
                  <Button
                    size="compact-xs"
                    variant="light"
                    leftSection={<IconUserCheck size={12} />}
                    onClick={() => {
                      setTarget(registration);
                      setStatus(
                        registration.attendanceStatus === 'REGISTERED'
                          ? 'PRESENT'
                          : registration.attendanceStatus,
                      );
                      setRemark(registration.attendanceRemark ?? '');
                    }}
                  >
                    {t('exam.candidates.record')}
                  </Button>
                </Table.Td>
              </Table.Tr>
            ))}
          </Table.Tbody>
        </Table>
      )}

      <Modal
        opened={Boolean(target)}
        onClose={() => setTarget(null)}
        title={t('exam.candidates.attendance')}
        size="md"
        radius="lg"
      >
        <Stack gap="sm">
          <Text fz="sm" fw={500}>
            {target ? candidateName(target) : ''} · {target?.admissionNumber}
          </Text>
          <Select
            label={t('exam.candidates.attendance')}
            data={OPTIONS.map((value) => ({
              value,
              label: t(`exam.attendance.${value}`),
            }))}
            value={status}
            onChange={(value) => setStatus((value as AttendanceStatus) ?? 'PRESENT')}
            size="sm"
          />
          <Textarea
            label={t('exam.candidates.remark')}
            minRows={2}
            autosize
            value={remark}
            onChange={(event) => setRemark(event.currentTarget.value)}
            required={NEEDS_REMARK.includes(status)}
          />
          <Group justify="flex-end">
            <Button variant="default" size="sm" onClick={() => setTarget(null)}>
              {t('exam.cancel')}
            </Button>
            <Button size="sm" loading={isLoading} onClick={save}>
              {t('exam.candidates.record')}
            </Button>
          </Group>
        </Stack>
      </Modal>
    </Paper>
  );
}
