// Import ejs
import ejs from 'ejs';

// Import dce-live-grouper
import {
  GrouperRequest,
  getGroupAssignment,
} from 'dce-live-grouper';

// Import dce-reactkit
import { genRouteHandler, ParamType } from '../../../../dce-reactkit';

// Import types
import Router from '../../../types/Router';

// Import shared types
import AssignToGroups from '../../../shared/types/AssignToGroups';
import AttendanceEntry from '../../../shared/types/AttendanceEntry';
import GetCourseEvent from '../../../shared/types/GetCourseEvent';
import RecordAttendanceFunction from '../../../shared/types/RecordAttendanceFunction';
import AttendanceMethod from '../../../shared/types/AttendanceMethod';
import ErrorCode from '../../../shared/types/ErrorCode';

// Import shared helpers
import genOccurrenceId from '../../../shared/helpers/genOccurrenceId';
import getTimeInfoInET from '../../../shared/helpers/getTimeInfoInET';
import toStringMMDDYY from '../../../shared/helpers/toStringMMDDYY';
import createOccurrence from '../../../shared/helpers/createOccurrence';
import findOccurrence from '../../../shared/helpers/findOccurrence';

// Import template
import checkInEJSTemplate from './checkInEJSTemplate';

/**
 * Main entrypoint for check-in, for login and attendance.
 * @author Benedikt Arnarsson
 * @author Gabe Abrams
 */
const addCheckInPageRoute = (
  router: Router,
  recordAttendance: RecordAttendanceFunction,
  getCourseEvent: GetCourseEvent,
) => {
  router.get(
    '/checkin/:ihid',
    genRouteHandler({
      paramTypes: {
        ihid: ParamType.String,
      },
      handler: async ({ params, send, renderErrorPage }) => {
        // Destructure params
        const {
          ihid,
          courseId,
          userId,
          userFirstName,
          userLastName,
          isLearner,
        } = params;

        // Check the user in
        try {
          // Create basic occurrence info
          const {
            day,
            month,
            year,
          } = getTimeInfoInET();
          const occurrenceBasicInfo = {
            courseId,
            ihid,
            day,
            month,
            year,
          };

          // Generate occurrence id
          const occurrenceId = genOccurrenceId(occurrenceBasicInfo);

          // Find occurrence
          let occurrence = await findOccurrence(occurrenceId);

          // If no occurrence, create one if possible
          if (!occurrence) {
            // Get course event
            const event = await getCourseEvent({
              courseId,
              ihid,
              requireNotArchived: true,
            });

            // Event not found
            if (!event) {
              // Cannot create occurrence because not held in person
              return renderErrorPage({
                title: 'Could not find event',
                description: 'Could not find event. Please double-check your URL or contact your instructor to set it up.',
                code: ErrorCode.EventNotFound,
              });
            }

            // Event is not held in person
            if (!event.inPersonConfig) {
              // Cannot create occurrence because not held in person
              return renderErrorPage({
                title: 'Event Not Held In Person',
                description: 'This event is not held in person, so you cannot check in. Please contact your instructor if you think this is wrong.',
                code: ErrorCode.EventNotHeldInPerson,
              });
            }

            // Occurrence cannot be created by a student
            if (event.inPersonConfig.assignToGroups !== AssignToGroups.Never) {
              return renderErrorPage({
                title: 'Event Not Started Yet',
                description: 'This event has not started yet, so you cannot check in. Please wait for your instructor to initialize check in.',
                code: ErrorCode.OccurrenceNotSetUpToday,
              });
            }

            // Student *can* create the occurrence themselves
            occurrence = {
              ...occurrenceBasicInfo,
              grouperEnabled: false,
            };
            await createOccurrence(occurrence);
          }

          // Handle grouping
          let groupNum: number | undefined;
          if (occurrence.grouperEnabled) {
            // Create grouper request
            const mmddyyStr = toStringMMDDYY({
              day,
              month,
              year,
            });
            const grouperRequest: GrouperRequest = {
              courseId,
              eventId: `${ihid}-O${mmddyyStr}`,
              studentId: userId,
            };

            // Run grouping algorithm
            const groupAssignment = await getGroupAssignment(grouperRequest);
            groupNum = groupAssignment.groupNum;
          }

          // Write attendance entry
          const attendanceEntry: AttendanceEntry = {
            userId,
            userFirstName,
            userLastName,
            courseId,
            ihid,
            isLearner,
            method: AttendanceMethod.InPerson,
            groupNum,
          };
          await recordAttendance(attendanceEntry);

          // Render check in results page
          const page = ejs.render(
            checkInEJSTemplate,
            {
              userFirstName,
              groupNum,
            },
          );

          return send(page);
        } catch (err) {
          // eslint-disable-next-line no-console
          console.log('Error:', err);
          return renderErrorPage({
            title: 'An Unknown Error Occurred',
            description: 'We couldn\'t check you in because an unknown error occurred. Try again. If the issue persists, contact your instructor.',
            code: ErrorCode.UnknownCheckInError,
          });
        }
      },
    }),
  );
};

export default addCheckInPageRoute;
