/* eslint-disable @next/next/no-img-element */
import Layout from "@/components/High/Layout";
import Button from "@/components/Low/Button";
import ProgressBar from "@/components/Low/ProgressBar";
import InviteWithUserCard from "@/components/Medium/InviteWithUserCard";
import ModuleBadge from "@/components/ModuleBadge";
import ProfileSummary from "@/components/ProfileSummary";
import {Session} from "@/hooks/useSessions";
import {Grading} from "@/interfaces";
import {EntityWithRoles} from "@/interfaces/entity";
import {Exam} from "@/interfaces/exam";
import {InviteWithUsers} from "@/interfaces/invite";
import {Assignment} from "@/interfaces/results";
import {Stat, User} from "@/interfaces/user";
import {sessionOptions} from "@/lib/session";
import useExamStore from "@/stores/examStore";
import {mapBy, serialize} from "@/utils";
import {activeAssignmentFilter} from "@/utils/assignments";
import {getAssignmentsByAssignee} from "@/utils/assignments.be";
import {getEntityWithRoles} from "@/utils/entities.be";
import {getExamsByIds} from "@/utils/exams.be";
import {getGradingSystemByEntity} from "@/utils/grading.be";
import {convertInvitersToUsers, getInvitesByInvitee} from "@/utils/invites.be";
import {countExamModules, countFullExams, MODULE_ARRAY, sortByModule, sortByModuleName} from "@/utils/moduleUtils";
import {checkAccess} from "@/utils/permissions";
import {getGradingLabel} from "@/utils/score";
import {getSessionsByUser} from "@/utils/sessions.be";
import {averageScore} from "@/utils/stats";
import {getStatsByUser} from "@/utils/stats.be";
import clsx from "clsx";
import {withIronSessionSsr} from "iron-session/next";
import {capitalize, uniqBy} from "lodash";
import moment from "moment";
import Head from "next/head";
import {useRouter} from "next/router";
import {BsBook, BsClipboard, BsFileEarmarkText, BsHeadphones, BsMegaphone, BsPen, BsPencil, BsStar} from "react-icons/bs";
import {ToastContainer} from "react-toastify";

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

export const getServerSideProps = withIronSessionSsr(async ({req, res}) => {
	const user = req.session.user as User | undefined;

	if (!user) {
		return {
			redirect: {
				destination: "/login",
				permanent: false,
			},
		};
	}

	if (!checkAccess(user, ["admin", "developer", "mastercorporate"]))
		return {
			redirect: {
				destination: "/dashboard",
				permanent: false,
			},
		};

	const entityIDS = mapBy(user.entities, "id") || [];
	const entityID = entityIDS.length > 0 ? entityIDS[0] : "";

	const entities = await getEntityWithRoles(entityID);
	const allAssignments = await getAssignmentsByAssignee(user.id, {archived: false});
	const stats = await getStatsByUser(user.id);
	const sessions = await getSessionsByUser(user.id, 10);
	const invites = await getInvitesByInvitee(user.id);
	const grading = await getGradingSystemByEntity(entityID);

	const formattedInvites = await Promise.all(invites.map(convertInvitersToUsers));
	const assignments = allAssignments.filter(activeAssignmentFilter);

	const examIDs = uniqBy(
		assignments.flatMap((a) =>
			a.exams.filter((e) => e.assignee === user.id).map((e) => ({module: e.module, id: e.id, key: `${e.module}_${e.id}`})),
		),
		"key",
	);
	const exams = await getExamsByIds(examIDs);

	return {props: serialize({user, entities, assignments, stats, exams, sessions, invites: formattedInvites, grading})};
}, sessionOptions);

export default function Dashboard({user, entities, assignments, stats, invites, grading, sessions, exams}: Props) {
	const router = useRouter();

	const setExams = useExamStore((state) => state.setExams);
	const setShowSolutions = useExamStore((state) => state.setShowSolutions);
	const setUserSolutions = useExamStore((state) => state.setUserSolutions);
	const setSelectedModules = useExamStore((state) => state.setSelectedModules);
	const setAssignment = useExamStore((state) => state.setAssignment);

	const startAssignment = (assignment: Assignment) => {
		if (exams.every((x) => !!x)) {
			setUserSolutions([]);
			setShowSolutions(false);
			setExams(exams.map((x) => x!).sort(sortByModule));
			setSelectedModules(
				exams
					.map((x) => x!)
					.sort(sortByModule)
					.map((x) => x!.module),
			);
			setAssignment(assignment);

			router.push("/exercises");
		}
	};

	const studentAssignments = assignments.filter(activeAssignmentFilter);

	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 />
			<Layout user={user}>
				{entities.length > 0 && (
					<div className="absolute right-4 top-4 rounded-lg bg-neutral-200 px-2 py-1">
						<b>{mapBy(entities, "label")?.join(", ")}</b>
					</div>
				)}

				<ProfileSummary
					user={user}
					items={[
						{
							icon: <BsFileEarmarkText className="w-6 h-6 md:w-8 md:h-8 text-mti-red-light" />,
							value: countFullExams(stats),
							label: "Exams",
							tooltip: "Number of all conducted completed exams",
						},
						{
							icon: <BsPencil className="w-6 h-6 md:w-8 md:h-8 text-mti-red-light" />,
							value: countExamModules(stats),
							label: "Modules",
							tooltip: "Number of all exam modules performed including Level Test",
						},
						{
							icon: <BsStar className="text-mti-red-light h-6 w-6 md:h-8 md:w-8" />,
							value: `${stats.length > 0 ? averageScore(stats) : 0}%`,
							label: "Average Score",
							tooltip: "Average success rate for questions responded",
						},
					]}
				/>

				{/* Bio */}
				<section className="flex flex-col gap-1 md:gap-3">
					<span className="text-lg font-bold">Bio</span>
					<span className="text-mti-gray-taupe">
						{user.bio || "Your bio will appear here, you can change it by clicking on your name in the top right corner."}
					</span>
				</section>

				{/* Assignments */}
				<section className="flex flex-col gap-1 md:gap-3">
					<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
							.sort((a, b) => moment(a.startDate).diff(b.startDate))
							.map((assignment) => (
								<div
									className={clsx(
										"border-mti-gray-anti-flash flex min-w-[350px] flex-col gap-6 rounded-xl border p-4",
										assignment.results.map((r) => r.user).includes(user.id) && "border-mti-green-light",
									)}
									key={assignment.id}>
									<div className="flex flex-col gap-1">
										<h3 className="text-mti-black/90 text-xl font-semibold">{assignment.name}</h3>
										<span className="flex justify-between gap-1 text-lg">
											<span>{moment(assignment.startDate).format("DD/MM/YY, HH:mm")}</span>
											<span>-</span>
											<span>{moment(assignment.endDate).format("DD/MM/YY, HH:mm")}</span>
										</span>
									</div>
									<div className="flex w-full items-center justify-between">
										<div className="-md:mt-2 grid w-fit min-w-[140px] grid-cols-2 grid-rows-2 place-items-center justify-between gap-4">
											{assignment.exams
												.filter((e) => e.assignee === user.id)
												.map((e) => e.module)
												.sort(sortByModuleName)
												.map((module) => (
													<ModuleBadge className="scale-110 w-full" key={module} module={module} />
												))}
										</div>
										{!assignment.results.map((r) => r.user).includes(user.id) && (
											<>
												<div
													className="tooltip flex h-full w-full items-center justify-end pl-8 md:hidden"
													data-tip="Your screen size is too small to perform an assignment">
													<Button className="h-full w-full !rounded-xl" variant="outline">
														Start
													</Button>
												</div>
												<div
													data-tip="You have already started this assignment!"
													className={clsx(
														"-md:hidden h-full w-full max-w-[50%] cursor-pointer",
														sessions.filter((x) => x.assignment?.id === assignment.id).length > 0 && "tooltip",
													)}>
													<Button
														className={clsx("w-full h-full !rounded-xl")}
														onClick={() => startAssignment(assignment)}
														variant="outline"
														disabled={sessions.filter((x) => x.assignment?.id === assignment.id).length > 0}>
														Start
													</Button>
												</div>
											</>
										)}
										{assignment.results.map((r) => r.user).includes(user.id) && (
											<Button
												onClick={() => router.push("/record")}
												color="green"
												className="-md:hidden h-full w-full max-w-[50%] !rounded-xl"
												variant="outline">
												Submitted
											</Button>
										)}
									</div>
								</div>
							))}
					</span>
				</section>

				{/* Invites */}
				{invites.length > 0 && (
					<section className="flex flex-col gap-1 md:gap-3">
						<span className="text-mti-gray-taupe scrollbar-hide flex gap-8 overflow-x-scroll">
							{invites.map((invite) => (
								<InviteWithUserCard key={invite.id} invite={invite} reload={() => router.replace(router.asPath)} />
							))}
						</span>
					</section>
				)}

				{/* Score History */}
				<section className="flex flex-col gap-3">
					<span className="text-lg font-bold">Score History</span>
					<div className="-md:grid-rows-4 grid gap-6 md:grid-cols-2">
						{MODULE_ARRAY.map((module) => {
							const desiredLevel = user.desiredLevels[module] || 9;
							const level = user.levels[module] || 0;
							return (
								<div className="border-mti-gray-anti-flash flex flex-col gap-2 rounded-xl border p-4" key={module}>
									<div className="flex items-center gap-2 md:gap-3">
										<div className="bg-mti-gray-smoke flex h-8 w-8 items-center justify-center rounded-lg md:h-12 md:w-12 md:rounded-xl">
											{module === "reading" && <BsBook className="text-ielts-reading h-4 w-4 md:h-5 md:w-5" />}
											{module === "listening" && <BsHeadphones className="text-ielts-listening h-4 w-4 md:h-5 md:w-5" />}
											{module === "writing" && <BsPen className="text-ielts-writing h-4 w-4 md:h-5 md:w-5" />}
											{module === "speaking" && <BsMegaphone className="text-ielts-speaking h-4 w-4 md:h-5 md:w-5" />}
											{module === "level" && <BsClipboard className="text-ielts-level h-4 w-4 md:h-5 md:w-5" />}
										</div>
										<div className="flex w-full justify-between">
											<span className="text-sm font-bold md:font-extrabold">{capitalize(module)}</span>
											<span className="text-mti-gray-dim text-sm font-normal">
												{module === "level" && !!grading && `English Level: ${getGradingLabel(level, grading.steps)}`}
												{module !== "level" && `Level ${level} / Level 9 (Desired Level: ${desiredLevel})`}
											</span>
										</div>
									</div>
									<div className="md:pl-14">
										<ProgressBar
											color={module}
											label=""
											mark={module === "level" ? undefined : Math.round((desiredLevel * 100) / 9)}
											markLabel={`Desired Level: ${desiredLevel}`}
											percentage={module === "level" ? level : Math.round((level * 100) / 9)}
											className="h-2 w-full"
										/>
									</div>
								</div>
							);
						})}
					</div>
				</section>
			</Layout>
		</>
	);
}
