import { apiFetchJson } from "../../../lib/api";
import type { ApiAssignment, ApiAssignmentStudentQuestionDetail, ApiListResponse } from "../../../lib/api-types";
import { studentDashboardLabels } from "../../../content/dashboard-labels";
import { getAssignmentReviewHref, getAssignmentWorkHref } from "../../../lib/routes";

type AssignmentFocusStat = {
	label: string;
	value: string;
};

type AssignmentFocusItem = {
	title: string;
	meta: string;
	subMeta: string;
	statusLabel: string;
	progressText: string;
	tone: "yellow" | "teal" | "blue";
	primaryLabel: string;
	primaryHref: string;
	secondaryLabel: string;
	secondaryHref: string;
};

type AssignmentFocusGroup = {
	title: string;
	description: string;
	items: AssignmentFocusItem[];
};

type DashboardAssignmentsFocusData = {
	stats: AssignmentFocusStat[];
	groups: AssignmentFocusGroup[];
};

const formatDueDate = (value: string | null) => {
	if (!value) return "No due date";

	return new Intl.DateTimeFormat("en-GB", {
		month: "short",
		day: "numeric",
	}).format(new Date(value));
};

const extractTopic = (assignment: ApiAssignment, questions: ApiAssignmentStudentQuestionDetail[]) => {
	const fromInstructions = assignment.instructions?.match(/^Topic:\s*(.+)$/i)?.[1]?.trim();
	if (fromInstructions) return fromInstructions;
	return questions[0]?.subject ?? "Assignment";
};

const deriveStatus = (assignment: ApiAssignment, questions: ApiAssignmentStudentQuestionDetail[]) => {
	const total = questions.length;
	const answered = questions.filter((question) => question.answer_id).length;
	const reviewed = questions.filter((question) => question.answer_status === "reviewed").length;

	if (answered === 0) return "NOT_STARTED" as const;
	if (reviewed === total || assignment.status === "closed") return "SUBMITTED" as const;
	return "IN_PROGRESS" as const;
};

const mapAssignmentItem = (assignment: ApiAssignment, questions: ApiAssignmentStudentQuestionDetail[]): AssignmentFocusItem => {
	const derivedStatus = deriveStatus(assignment, questions);
	const answered = questions.filter((question) => question.answer_id).length;
	const reviewed = questions.filter((question) => question.answer_status === "reviewed").length;
	const topic = extractTopic(assignment, questions);

	if (derivedStatus === "SUBMITTED") {
		return {
			title: assignment.title,
			meta: topic,
			subMeta: `${reviewed}/${questions.length} reviewed · Due ${formatDueDate(assignment.due_at)}`,
			statusLabel: "Completed",
			progressText: `${reviewed}/${questions.length} reviewed`,
			tone: "teal",
			primaryLabel: "Open review",
			primaryHref: getAssignmentReviewHref("student", assignment.id),
			secondaryLabel: "Open workspace",
			secondaryHref: getAssignmentWorkHref(assignment.id),
		};
	}

	if (derivedStatus === "IN_PROGRESS") {
		return {
			title: assignment.title,
			meta: topic,
			subMeta: `${answered}/${questions.length} answered · Due ${formatDueDate(assignment.due_at)}`,
			statusLabel: "In progress",
			progressText: `${answered}/${questions.length} answered`,
			tone: "blue",
			primaryLabel: "Resume work",
			primaryHref: getAssignmentWorkHref(assignment.id),
			secondaryLabel: "See review",
			secondaryHref: getAssignmentReviewHref("student", assignment.id),
		};
	}

	return {
		title: assignment.title,
		meta: topic,
		subMeta: `Due ${formatDueDate(assignment.due_at)} · Ready when you are`,
		statusLabel: "Ready to start",
		progressText: `${questions.length} questions`,
		tone: "yellow",
		primaryLabel: "Start assignment",
		primaryHref: getAssignmentWorkHref(assignment.id),
		secondaryLabel: "See review",
		secondaryHref: getAssignmentReviewHref("student", assignment.id),
	};
};

export const getDashboardAssignmentsFocusData = async (studentId: number): Promise<DashboardAssignmentsFocusData> => {
	const assignmentsResponse = await apiFetchJson<ApiListResponse<ApiAssignment>>(`/api/students/${studentId}/assignments`);
	const assignmentDetails = await Promise.all(
		assignmentsResponse.data.map(async (assignment) => ({
			assignment,
			questions: (await apiFetchJson<ApiListResponse<ApiAssignmentStudentQuestionDetail>>(`/api/assignments/${assignment.id}/students/${studentId}/questions`)).data,
		})),
	);

	const items = assignmentDetails.map(({ assignment, questions }) => ({
		assignment,
		questions,
		item: mapAssignmentItem(assignment, questions),
		derivedStatus: deriveStatus(assignment, questions),
	}));

	const completed = items.filter((entry) => entry.derivedStatus === "SUBMITTED");
	const inProgress = items.filter((entry) => entry.derivedStatus === "IN_PROGRESS");
	const notStarted = items.filter((entry) => entry.derivedStatus === "NOT_STARTED");
	const liveItems = items.filter((entry) => entry.derivedStatus !== "SUBMITTED");
	const nextDue = liveItems
		.map((entry) => entry.assignment.due_at)
		.filter((value): value is string => Boolean(value))
		.sort((left, right) => new Date(left).getTime() - new Date(right).getTime())[0] ?? null;
	const completionPercentages = assignmentDetails.map(({ assignment, questions }) => {
		const reviewed = questions.filter((question) => question.answer_status === "reviewed").length;
		if (assignment.status === "closed") return 100;
		if (questions.length === 0) return 0;
		return Math.round((reviewed / questions.length) * 100);
	});
	const averageCompletion = completionPercentages.length
		? Math.round(completionPercentages.reduce((sum, value) => sum + value, 0) / completionPercentages.length)
		: 0;

	return {
		stats: [
			{ label: studentDashboardLabels.assignments.liveNow, value: `${inProgress.length + notStarted.length}` },
			{ label: studentDashboardLabels.assignments.completed, value: `${completed.length}` },
			{ label: studentDashboardLabels.assignments.averageReviewed, value: `${averageCompletion}%` },
			{ label: studentDashboardLabels.assignments.nextDue, value: formatDueDate(nextDue) },
		],
		groups: [
			{
				title: "Continue now",
				description: "Assignments that already have momentum and are best finished next.",
				items: inProgress.map((entry) => entry.item),
			},
			{
				title: "Coming up",
				description: "Work that is live but not started yet, so you can choose what to begin early.",
				items: notStarted.map((entry) => entry.item),
			},
			{
				title: "Completed",
				description: "Reviewed work you can revisit for correction and confidence boosts.",
				items: completed.map((entry) => entry.item),
			},
		].filter((group) => group.items.length > 0),
	};
};
