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

/** 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, refetch } = useGetExamRegistrationsQuery(examId);
  const [recordAttendance, { isLoading }] = useRecordAttendanceMutation();
  const [regradeAttempt] = useRegradeAttemptMutation();
  const [regrading, setRegrading] = useState<string | null>(null);
  const [target, setTarget] = useState<ExamRegistration | null>(null);
  const [status, setStatus] = useState<AttendanceStatus>('PRESENT');
  const [remark, setRemark] = useState('');
  const table = useServerTable();

  const regrade = async (registration: ExamRegistration) => {
    const attemptId = registration.attempt?.id;
    if (!attemptId) return;
    setRegrading(attemptId);
    try {
      const outcome = await regradeAttempt(attemptId).unwrap();
      if (outcome.graded) {
        notify.success(t('exam.candidates.regraded'));
      } else {
        notify.error(t('exam.candidates.regradeNotEligible', { reason: outcome.reason }));
      }
      refetch();
    } catch (error) {
      notify.error(extractErrorMessage(error, t('exam.candidates.regradeError')));
    } finally {
      setRegrading(null);
    }
  };

  const startRecording = (registration: ExamRegistration) => {
    setTarget(registration);
    setStatus(
      registration.attendanceStatus === 'REGISTERED'
        ? 'PRESENT'
        : registration.attendanceStatus,
    );
    setRemark(registration.attendanceRemark ?? '');
  };

  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;

  const paged = table.paginate(registrations ?? []);

  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>
      ) : (
        <AdvancedTable
          tableName={t('exam.candidates.section')}
          columns={examCandidateColumns(t, {
            onRecord: startRecording,
            onRegrade: regrade,
            regrading,
          })}
          data={paged.rows}
          itemCount={paged.itemCount}
          pageIndex={paged.pageIndex}
          onPageChange={table.setPageIndex}
          pageSize={table.pageSize}
          refresh={refetch}
        />
      )}

      <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>
  );
}
