/* eslint-disable @next/next/no-img-element */
import Head from "next/head";
import { withIronSessionSsr } from "iron-session/next";
import { sessionOptions } from "@/lib/session";
import { Stat, User } from "@/interfaces/user";
import { useEffect, useMemo, useState } from "react";
import useFilterRecordsByUser from "@/hooks/useFilterRecordsByUser";
import { groupByDate } from "@/utils/stats";
import moment from "moment";
import { ToastContainer } from "react-toastify";
import clsx from "clsx";
import { shouldRedirectHome } from "@/utils/navigation.disabled";
import { uuidv4 } from "@firebase/util";
import { usePDFDownload } from "@/hooks/usePDFDownload";
import useRecordStore from "@/stores/recordStore";
import StatsGridItem from "@/components/Medium/StatGridItem";
import RecordFilter from "@/components/Medium/RecordFilter";
import { useRouter } from "next/router";
import useTrainingContentStore from "@/stores/trainingContentStore";
import { Assignment } from "@/interfaces/results";
import { getEntitiesUsers, getUsers } from "@/utils/users.be";
import { getAssignments, getEntitiesAssignments } from "@/utils/assignments.be";
import { findBy, mapBy, redirect, serialize } from "@/utils";
import { getEntitiesWithRoles } from "@/utils/entities.be";
import { checkAccess } from "@/utils/permissions";
import {
  getGradingSystemByEntities,
} from "@/utils/grading.be";
import { Grading } from "@/interfaces";
import { EntityWithRoles } from "@/interfaces/entity";
import CardList from "@/components/High/CardList";
import { requestUser } from "@/utils/api";
import { useAllowedEntities } from "@/hooks/useEntityPermissions";
import getPendingEvals from "@/utils/disabled.be";
import useEvaluationPolling from "@/hooks/useEvaluationPolling";

export const getServerSideProps = withIronSessionSsr(async ({ req, res }) => {
  const user = await requestUser(req, res);
  if (!user) return redirect("/login");

  if (shouldRedirectHome(user)) return redirect("/");

  const entityIDs = mapBy(user.entities, "id");
  const isAdmin = checkAccess(user, ["admin", "developer"]);

  const entities = await getEntitiesWithRoles(isAdmin ? undefined : entityIDs);
  const entitiesIds = mapBy(entities, "id");
  const [users, assignments, gradingSystems, pendingSessionIds] =
    await Promise.all([
      isAdmin ? getUsers() : getEntitiesUsers(entitiesIds),
      isAdmin ? getAssignments() : getEntitiesAssignments(entitiesIds),
      getGradingSystemByEntities(entitiesIds),
      getPendingEvals(user.id),
    ]);

  return {
    props: serialize({
      user,
      users,
      assignments,
      entities,
      gradingSystems,
      isAdmin,
      pendingSessionIds,
    }),
  };
}, sessionOptions);

type Filter = "months" | "weeks" | "days" | "assignments" | undefined;

interface Props {
  user: User;
  users: User[];
  assignments: Assignment[];
  entities: EntityWithRoles[];
  gradingSystems: Grading[];
  pendingSessionIds: string[];
  isAdmin: boolean;
}

const MAX_TRAINING_EXAMS = 10;

export default function History({
  user,
  users,
  assignments,
  entities,
  gradingSystems,
  isAdmin,
  pendingSessionIds,
}: Props) {
  const router = useRouter();
  const [statsUserId, setStatsUserId, training, setTraining] = useRecordStore(
    (state) => [
      state.selectedUser,
      state.setSelectedUser,
      state.training,
      state.setTraining,
    ]
  );

  const [filter, setFilter] = useState<Filter>();

  const { data: stats, isLoading: isStatsLoading } = useFilterRecordsByUser<
    Stat[]
  >(statsUserId || user?.id);
  const allowedDownloadEntities = useAllowedEntities(
    user,
    entities,
    "download_student_record"
  );

  const renderPdfIcon = usePDFDownload("stats");

  const [selectedTrainingExams, setSelectedTrainingExams] = useState<string[]>(
    []
  );
  const setTrainingStats = useTrainingContentStore((state) => state.setStats);

  const groupedStats = useMemo(
    () =>
      groupByDate(
        stats.filter((x) => {
          if (
            (x.module === "writing" || x.module === "speaking") &&
            !x.isDisabled &&
            Array.isArray(x.solutions) &&
            !x.solutions.every((y) => Object.keys(y).includes("evaluation"))
          )
            return false;
          return true;
        })
      ),
    [stats]
  );

  useEffect(() => setStatsUserId(user.id), [setStatsUserId, user]);

  useEffect(() => {
    const handleRouteChange = (url: string) => {
      setTraining(false);
    };
    router.events.on("routeChangeStart", handleRouteChange);
    return () => {
      router.events.off("routeChangeStart", handleRouteChange);
    };
  }, [router.events, setTraining]);

  const filterStatsByDate = (stats: { [key: string]: Stat[] }) => {
    if (filter && filter !== "assignments") {
      const filterDate = moment()
        .subtract({ [filter as string]: 1 })
        .format("x");
      const filteredStats: { [key: string]: Stat[] } = {};

      Object.keys(stats).forEach((timestamp) => {
        if (timestamp >= filterDate)
          filteredStats[timestamp] = stats[timestamp];
      });
      return filteredStats;
    }

    if (filter && filter === "assignments") {
      const filteredStats: { [key: string]: Stat[] } = {};

      Object.keys(stats).forEach((timestamp) => {
        if (
          stats[timestamp]
            .map((s) => s.assignment === undefined)
            .includes(false)
        )
          filteredStats[timestamp] = [
            ...stats[timestamp].filter((s) => !!s.assignment),
          ];
      });

      return filteredStats;
    }

    return stats;
  };

  const handleTrainingContentSubmission = () => {
    if (groupedStats) {
      const groupedStatsByDate = filterStatsByDate(groupedStats);
      const allStats = Object.keys(groupedStatsByDate);
      const selectedStats = selectedTrainingExams.reduce<
        Record<string, Stat[]>
      >((accumulator, moduleAndTimestamp) => {
        const timestamp = moduleAndTimestamp.split("-")[1];
        if (
          allStats.includes(timestamp) &&
          !accumulator.hasOwnProperty(timestamp)
        ) {
          accumulator[timestamp] = groupedStatsByDate[timestamp];
        }
        return accumulator;
      }, {});
      setTrainingStats(Object.values(selectedStats).flat());
      router.push("/training");
    }
  };

  const filteredStats = useMemo(
    () =>
      Object.keys(filterStatsByDate(groupedStats)).sort(
        (a, b) => parseInt(b) - parseInt(a)
      ),
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [groupedStats, filter]
  );

  const customContent = (timestamp: string) => {
    const dateStats = groupedStats[timestamp];
    const statUser = findBy(users, "id", dateStats[0]?.user);

    const canDownload = mapBy(statUser?.entities, "id").some((e) =>
      mapBy(allowedDownloadEntities, "id").includes(e)
    );

    return (
      <StatsGridItem
        key={uuidv4()}
        stats={dateStats}
        gradingSystems={gradingSystems}
        timestamp={timestamp}
        user={user}
        assignments={assignments}
        users={users}
        training={training}
        selectedTrainingExams={selectedTrainingExams}
        setSelectedTrainingExams={setSelectedTrainingExams}
        maxTrainingExams={MAX_TRAINING_EXAMS}
        renderPdfIcon={canDownload ? renderPdfIcon : undefined}
      />
    );
  };

  useEvaluationPolling(
    pendingSessionIds ? pendingSessionIds : [],
    "records",
    user.id
  );

  return (
    <>
      <Head>
        <title>Record | 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 />
      {user && (
        <>
          <RecordFilter
            user={user}
            isAdmin={isAdmin}
            entities={entities}
            filterState={{ filter: filter, setFilter: setFilter }}
          >
            {training && (
              <div className="flex flex-row">
                <div className="font-semibold text-2xl mr-4">
                  Select up to 10 exercises
                  {`(${selectedTrainingExams.length}/${MAX_TRAINING_EXAMS})`}
                </div>
                <button
                  className={clsx(
                    "bg-mti-purple-ultralight text-mti-purple px-4 py-2 rounded-full hover:text-white hover:bg-mti-purple-light ml-4 disabled:cursor-not-allowed",
                    "transition duration-300 ease-in-out"
                  )}
                  disabled={selectedTrainingExams.length == 0}
                  onClick={handleTrainingContentSubmission}
                >
                  Submit
                </button>
              </div>
            )}
          </RecordFilter>

          {filteredStats.length > 0 && !isStatsLoading && (
            <CardList
              list={filteredStats}
              renderCard={customContent}
              searchFields={[]}
              pageSize={30}
              className="lg:!grid-cols-3"
            />
          )}
          {filteredStats.length === 0 && !isStatsLoading && (
            <span className="font-semibold ml-1">No record to display...</span>
          )}
          {isStatsLoading && (
            <div className="absolute left-1/2 top-1/2 flex h-fit w-fit -translate-x-1/2 -translate-y-1/2 animate-pulse flex-col items-center gap-12">
              <span className="loading loading-infinity w-32 bg-mti-green-light" />
            </div>
          )}
        </>
      )}
    </>
  );
}
