import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
  Modal,
  Stack,
  Select,
  Divider,
  Text,
  Badge,
  Paper,
  SimpleGrid,
  Group,
  TextInput,
  Button,
  Alert,
} from '@mantine/core';
import { IconInfoCircle, IconCheck, IconX } from '@tabler/icons-react';
import { AdvancedTable, ModalFooter, notify, useServerTable } from '@ema-platform/ui';
import { extractErrorMessage } from '@ema-platform/api';
import { LICENSE_PERMISSIONS, RequirePermission } from '@ema-platform/auth';
import { recordResultColumns } from './columns';
import { useCreateResultMutation } from '../../api/result-api';
import { useGetExamRegistrationsQuery, useGetGradingSheetQuery } from '../../../exam/api/exam-api';
import type { Exam } from '../../../exam/types/exam';

function InfoRow({ label, value }: { label: string; value: string }) {
  return (
    <div>
      <Text fz="xs" c="dimmed" tt="uppercase" fw={600}>{label}</Text>
      <Text fz="sm" fw={500}>{value || '—'}</Text>
    </div>
  );
}

export function RecordResultModal({
  exam,
  opened,
  onClose,
}: {
  exam: Exam;
  opened: boolean;
  onClose: () => void;
}) {
  const { t, i18n } = useTranslation();
  const locale = i18n.language as 'en' | 'am';
  const [seafarerSearch, setSeafarerSearch] = useState('');
  const [selectedSeafarerId, setSelectedSeafarerId] = useState<string | null>(null);
  const [scores, setScores] = useState<Record<string, number>>({});
  const [questionRemarks, setQuestionRemarks] = useState<Record<string, string>>({});
  const [remark, setRemark] = useState('');

  // Only candidates who registered and actually sat the paper can be marked
  // (US-EXAM-009 feeding US-EXAM-011) — the API refuses anyone else, so the
  // picker is the session's own register rather than every seafarer profile.
  const { data: registrations } = useGetExamRegistrationsQuery(exam.id, {
    skip: !opened,
  });
  // The candidate's own answers plus whatever score auto-grading could
  // already compute for the CHOICE portion — degrades to "no data" for an
  // OFFLINE candidate or one who never sat an online attempt, same as
  // before this existed.
  const { data: gradingSheet } = useGetGradingSheetQuery(
    { examId: exam.id, profileId: selectedSeafarerId ?? '' },
    { skip: !opened || !selectedSeafarerId },
  );
  const answersByQuestion = new Map(
    (gradingSheet?.questions ?? []).map((q) => [q.questionId, q]),
  );
  const [createResult, { isLoading: isSaving }] = useCreateResultMutation();
  const table = useServerTable();

  const questions = exam.questions ?? [];
  const pagedQuestions = table.paginate(questions);

  // Prefill (never override) the CHOICE questions auto-grading already
  // scored — the examiner only has to key in the ESSAY marks. A fresh
  // seafarer selection always starts from an empty scores map, so this
  // only ever fills in blanks, never stomps a manual edit already made.
  useEffect(() => {
    if (!gradingSheet) return;
    const autoScores: Record<string, number> = {};
    for (const q of gradingSheet.questions) {
      if (q.autoScore !== null) autoScores[q.questionId] = q.autoScore;
    }
    if (Object.keys(autoScores).length) {
      setScores((prev) => ({ ...autoScores, ...prev }));
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [gradingSheet]);

  const seafarerOptions = (registrations ?? [])
    .filter((registration) =>
      ['PRESENT', 'LATE'].includes(registration.attendanceStatus),
    )
    .map((registration) => ({
      value: registration.profileId,
      label: `${registration.admissionNumber} — ${[
        registration.profile?.firstName,
        registration.profile?.middleName,
        registration.profile?.lastName,
      ]
        .filter(Boolean)
        .join(' ')}`,
    }));

  const filteredOptions = seafarerSearch
    ? seafarerOptions.filter((o: any) => o.label.toLowerCase().includes(seafarerSearch.toLowerCase()))
    : seafarerOptions;

  const totalScore = questions.reduce((sum, q) => sum + (scores[q.id] ?? 0), 0);
  const maxScore = questions.reduce((sum, q) => sum + (q.points ?? 0), 0);
  // The cutting point is read per the exam's configured evaluation method —
  // an AVERAGE or PERCENTAGE exam must not be graded as a raw sum.
  const effectiveScore =
    exam.evaluationMethod === 'AVERAGE'
      ? questions.length > 0
        ? totalScore / questions.length
        : 0
      : exam.evaluationMethod === 'PERCENTAGE'
        ? maxScore > 0
          ? (totalScore / maxScore) * 100
          : 0
        : totalScore;
  const passed = effectiveScore >= exam.cuttingPoint;

  const handleScoreChange = (questionId: string, value: number) => {
    setScores((prev) => ({ ...prev, [questionId]: value }));
  };

  const handleQuestionRemarkChange = (questionId: string, value: string) => {
    setQuestionRemarks((prev) => ({ ...prev, [questionId]: value }));
  };

  const handleSave = async () => {
    if (!selectedSeafarerId) {
      notify.error(t('result.recordModal.seafarerRequired'));
      return;
    }
    try {
      const breakdowns = questions.map((q) => ({
        questionId: q.id,
        score: scores[q.id] ?? 0,
        remark: questionRemarks[q.id] ?? '',
      }));
      // The outcome is not sent: the API derives PASSED/FAILED from the
      // session's evaluation method and cutting point, and stamps the
      // examiner on the row (US-EXAM-011). The preview below shows what that
      // computation will produce.
      await createResult({
        seafarerId: selectedSeafarerId,
        examId: exam.id,
        resultBreakdowns: breakdowns,
        remark: remark ? { en: remark, am: '' } : undefined,
      }).unwrap();
      notify.success(t('result.recordModal.saveSuccess'));
      setSelectedSeafarerId(null);
      setScores({});
      setQuestionRemarks({});
      setRemark('');
      setSeafarerSearch('');
      onClose();
    } catch (error) {
      const key = extractErrorMessage(error, t('result.recordModal.saveError'));
      notify.error(
        key === 'candidate_not_registered'
          ? 'This candidate is not registered for the session.'
          : key.startsWith('candidate_not_present')
            ? `No paper to mark — the register says ${key.split(':')[1] ?? ''}.`
            : key === 'result_already_recorded'
              ? 'A result has already been recorded for this candidate.'
              : key,
      );
    }
  };

  return (
    <Modal opened={opened} onClose={onClose} title={`${t('result.recordModal.title')} — ${exam.title[locale]}`} size="lg" radius="lg">
      <Stack gap="md">
        <Select
          label={t('result.recordModal.seafarer')}
          placeholder={t('result.recordModal.seafarerPlaceholder')}
          data={filteredOptions}
          value={selectedSeafarerId}
          onChange={(v) => {
            setSelectedSeafarerId(v);
            setScores({});
            setQuestionRemarks({});
          }}
          searchable
          onSearchChange={setSeafarerSearch}
          size="sm"
          required
        />

        {selectedSeafarerId && questions.length > 0 && (
          <>
            <Divider label={t('result.recordModal.scorePerQuestion')} labelPosition="center" />
            <AdvancedTable
              tableName={t('result.recordModal.title')}
              columns={recordResultColumns(t, locale, {
                scores,
                questionRemarks,
                onScoreChange: handleScoreChange,
                onRemarkChange: handleQuestionRemarkChange,
                answersByQuestion,
              })}
              data={pagedQuestions.rows}
              itemCount={pagedQuestions.itemCount}
              pageIndex={pagedQuestions.pageIndex}
              onPageChange={table.setPageIndex}
              pageSize={table.pageSize}
            />

            <Paper withBorder p="sm" radius="md" bg="gray.0">
              <SimpleGrid cols={3} spacing="sm">
                <InfoRow label={t('result.recordModal.totalScore')} value={String(totalScore)} />
                <InfoRow label={t('result.recordModal.passMark')} value={String(exam.cuttingPoint)} />
                <div>
                  <Text fz="xs" c="dimmed" tt="uppercase" fw={600}>{t('result.recordModal.status')}</Text>
                  <Group gap={4} mt={2}>
                    {passed
                      ? <><IconCheck size={14} color="var(--mantine-color-teal-6)" /><Text fz="sm" fw={700} c="teal">{t('result.recordModal.passed')}</Text></>
                      : <><IconX size={14} color="var(--mantine-color-red-6)" /><Text fz="sm" fw={700} c="red">{t('result.recordModal.failed')}</Text></>}
                  </Group>
                </div>
              </SimpleGrid>
            </Paper>

            <TextInput
              label={t('result.recordModal.remarkOptional')}
              placeholder={t('result.recordModal.remarkPlaceholder')}
              value={remark}
              onChange={(e) => setRemark(e.currentTarget.value)}
              size="sm"
            />

            <ModalFooter>
              <Button variant="default" onClick={onClose} size="sm">{t('result.cancel')}</Button>
              <RequirePermission anyOf={[LICENSE_PERMISSIONS.RECORD_EXAM_RESULT]} hideOnly>
                <Button onClick={handleSave} size="sm" loading={isSaving}>
                  {t('result.saveResult')}
                </Button>
              </RequirePermission>
            </ModalFooter>
          </>
        )}

        {selectedSeafarerId && questions.length === 0 && (
          <Alert color="yellow" icon={<IconInfoCircle size={15} />}>
            {t('result.recordModal.noQuestions')}
          </Alert>
        )}
      </Stack>
    </Modal>
  );
}
