/* eslint-disable @next/next/no-img-element */
import AssignmentCard from "@/components/High/AssignmentCard";
import Button from "@/components/Low/Button";
import Separator from "@/components/Low/Separator";
import ProfileSummary from "@/components/ProfileSummary";
import { Session } from "@/hooks/useSessions";
import { Grading, Module } from "@/interfaces";
import { EntityWithRoles } from "@/interfaces/entity";
import { Exam } from "@/interfaces/exam";
import { InviteWithEntity } from "@/interfaces/invite";
import { Assignment } from "@/interfaces/results";
import { Stat, User } from "@/interfaces/user";
import { sessionOptions } from "@/lib/session";
import useExamStore from "@/stores/exam";
import { findBy, mapBy, redirect, serialize } from "@/utils";
import { requestUser } from "@/utils/api";
import {
  activeAssignmentFilter,
  futureAssignmentFilter,
} from "@/utils/assignments";
import { getAssignmentsByAssignee } from "@/utils/assignments.be";
import { getExamsByIds } from "@/utils/exams.be";
import { sortByModule } from "@/utils/moduleUtils";
import { checkAccess } from "@/utils/permissions";
import { getSessionsByUser } from "@/utils/sessions.be";
import axios from "axios";
import clsx from "clsx";
import { withIronSessionSsr } from "iron-session/next";
import { uniqBy } from "lodash";
import Head from "next/head";
import { useRouter } from "next/router";
import { useMemo, useState } from "react";
import { BsArrowRepeat } from "react-icons/bs";
import { ToastContainer } from "react-toastify";

interface Props {
  user: User;
  entities: EntityWithRoles[];
  assignments: Assignment[];
  stats: Stat[];
  exams: Exam[];
  sessions: Session[];
  invites: InviteWithEntity[];
  grading: Grading;
}

export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
  const user = await requestUser(req, res);
  const destination = Buffer.from(req.url || "/").toString("base64");
  if (!user) return redirect(`/login?destination=${destination}`);

  if (!checkAccess(user, ["admin", "developer", "student"]))
    return redirect("/");
  const assignments = (await getAssignmentsByAssignee(
    user.id,
    {
      archived: { $ne: true },
    },
    {
      _id: 0,
      id: 1,
      name: 1,
      startDate: 1,
      endDate: 1,
      exams: 1,
      results: 1,
    },
    {
      sort: { startDate: 1 },
    }
  )) as Assignment[];

  const sessions = await getSessionsByUser(
    user.id,
    0,
    {
      "assignment.id": { $in: mapBy(assignments, "id") },
    },
    {
      _id: 0,
      id: 1,
      assignment: 1,
    }
  );

  const examIDs = uniqBy(
    assignments.reduce<{ module: Module; id: string; key: string }[]>(
      (acc, a) => {
        a.exams.forEach((e) => {
          if (e.assignee === user.id)
            acc.push({
              module: e.module,
              id: e.id,
              key: `${e.module}_${e.id}`,
            });
        });
        return acc;
      },
      []
    ),
    "key"
  );

  const exams = await getExamsByIds(examIDs);

  return { props: serialize({ user, assignments, exams, sessions }) };
}, sessionOptions);

const destination = Buffer.from("/official-exam").toString("base64");

export default function OfficialExam({
  user,
  entities,
  assignments,
  sessions,
  exams,
}: Props) {
  const [isLoading, setIsLoading] = useState(false);

  const router = useRouter();

  const dispatch = useExamStore((state) => state.dispatch);

  const reload = () => {
    setIsLoading(true);
    router.replace(router.asPath);
    setTimeout(() => setIsLoading(false), 500);
  };

  const startAssignment = (assignment: Assignment) => {
    const assignmentExams = exams.filter((e) => {
      const exam = findBy(assignment.exams, "id", e.id);
      return !!exam && exam.module === e.module;
    });

    if (assignmentExams.every((x) => !!x)) {
      const sortedAssignmentExams = assignmentExams.sort(sortByModule);
      dispatch({
        type: "INIT_EXAM",
        payload: {
          exams: sortedAssignmentExams,
          modules: mapBy(sortedAssignmentExams, "module"),
          assignment,
        },
      });
      router.push(
        `/exam?assignment=${assignment.id}&destination=${destination}`
      );
    }
  };

  const loadSession = async (session: Session) => {
    dispatch({ type: "SET_SESSION", payload: { session } });
    router.push(
      `/exam?assignment=${session.assignment?.id}&destination=${destination}`
    );
  };

  const logout = async () => {
    axios.post("/api/logout").finally(() => {
      setTimeout(() => router.reload(), 500);
    });
  };

  const studentAssignments = useMemo(
    () => [
      ...assignments.filter(activeAssignmentFilter),
      ...assignments.filter(futureAssignmentFilter),
    ],
    [assignments]
  );

  const assignmentSessions = useMemo(() => {
    const studentAssignmentsIDs = mapBy(studentAssignments, "id");
    return sessions.filter((s) =>
      studentAssignmentsIDs.includes(s.assignment?.id || "")
    );
  }, [sessions, studentAssignments]);

  const entityLabels = useMemo(
    () => mapBy(entities, "label")?.join(","),
    [entities]
  );

  return (
    <>
      <Head>
        <title>EnCoach</title>
        <meta
          name="description"
          content="A training platform for the IELTS exam provided by the Muscat Training Institute and developed by eCrop."
        />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <ToastContainer />
      <>
        {entities.length > 0 && (
          <div className="absolute right-4 top-4 rounded-lg bg-neutral-200 px-2 py-1">
            <b>{entityLabels}</b>
          </div>
        )}

        <ProfileSummary user={user} items={[]} removeLevel />

        <Separator />

        {/* Assignments */}
        <section className="flex flex-col gap-1 md:gap-3">
          <div
            onClick={reload}
            className="text-mti-purple-light hover:text-mti-purple-dark flex cursor-pointer items-center gap-2 transition duration-300 ease-in-out"
          >
            <span className="text-mti-black text-lg font-bold">
              Assignments
            </span>
            <BsArrowRepeat
              className={clsx("text-xl", isLoading && "animate-spin")}
            />
          </div>
          <span className="text-mti-gray-taupe scrollbar-hide flex gap-8 overflow-x-scroll">
            {studentAssignments.length === 0 &&
              "Assignments will appear here. It seems that for now there are no assignments for you."}
            {studentAssignments.map((a) => (
              <AssignmentCard
                key={a.id}
                assignment={a}
                user={user}
                session={assignmentSessions.find(
                  (s) => s.assignment?.id === a.id
                )}
                startAssignment={startAssignment}
                resumeAssignment={loadSession}
              />
            ))}
          </span>
        </section>

        <Button
          onClick={logout}
          variant="outline"
          color="red"
          className="max-w-[200px] w-full absolute bottom-8 left-8"
        >
          Sign out
        </Button>
      </>
    </>
  );
}
