import { apiFetchJson } from "../../../lib/api";
import type { ApiAssignment, ApiAssignmentStudentQuestionDetail, ApiClassroom, ApiListResponse, ApiReviewQueueItem, ApiReviewSummary, ApiStudent } from "../../../lib/api-types";
import {
	getAssignmentReviewHref,
	getDashboardTeacherClassroomHref,
} from "../../../lib/routes";
import { teacherDashboardLabels } from "../../../content/dashboard-labels";
import { isIndividualRedoAssignment } from "./dashboard-teacher-assignments.data";
import {
	buildTeacherShell,
	formatRelativeTime,
	formatShortDate,
	formatCombinedScoreLabel,
	initialsFor,
	queueStatusLabel,
	queueStatusTone,
	studentNote,
} from "./dashboard-teacher-classroom-detail.helpers";
import type { TeacherClassroomDetailData, TeacherClassroomRedoAssignmentItem } from "./dashboard-teacher-classroom-detail.types";

export type { TeacherClassroomDetailData, TeacherClassroomDetailStudentItem, TeacherClassroomRedoAssignmentItem } from "./dashboard-teacher-classroom-detail.types";

export const getTeacherClassroomDetailData = async (
	teacherId: number,
	classroomId: number,
	selectedStudentId?: number | null,
): Promise<TeacherClassroomDetailData | null> => {
	const [classroomsResponse, assignmentsResponse] = await Promise.all([
		apiFetchJson<ApiListResponse<ApiClassroom>>(`/api/teachers/${teacherId}/classrooms`),
		apiFetchJson<ApiListResponse<ApiAssignment>>(`/api/teachers/${teacherId}/assignments`),
	]);

	const classrooms = classroomsResponse.data;
	const classroom = classrooms.find((entry) => entry.id === classroomId);
	if (!classroom) return null;

	const classroomAssignments = assignmentsResponse.data.filter((assignment) => assignment.classroom_id === classroomId);
	const redoAssignments = classroomAssignments.filter(isIndividualRedoAssignment);

	const [studentsResponse, reviewSummaryEntries, reviewQueueEntries] = await Promise.all([
		apiFetchJson<ApiListResponse<ApiStudent>>(`/api/classrooms/${classroomId}/students`),
		Promise.all(classroomAssignments.map(async (assignment) => [assignment.id, await apiFetchJson<ApiReviewSummary>(`/api/assignments/${assignment.id}/review-summary`)] as const)),
		Promise.all(redoAssignments.map(async (assignment) => [assignment.id, (await apiFetchJson<ApiListResponse<ApiReviewQueueItem>>(`/api/assignments/${assignment.id}/review`)).data] as const)),
	]);

	const students = studentsResponse.data.slice().sort((left, right) => left.full_name.localeCompare(right.full_name));
	const reviewSummaryByAssignment = new Map(reviewSummaryEntries);
	const reviewQueueByAssignment = new Map(reviewQueueEntries);
	const scoredAssignments = classroomAssignments.filter((assignment) => assignment.status !== "draft");

	const studentScoreEntries = await Promise.all(
		students.map(async (student) => {
			const scoreRows = await Promise.all(
				scoredAssignments.map(async (assignment) => {
					const questions = (
						await apiFetchJson<ApiListResponse<ApiAssignmentStudentQuestionDetail>>(`/api/assignments/${assignment.id}/students/${student.id}/questions`)
					).data;
					const overallScore = questions.find((question) => typeof question.overall_score === "number")?.overall_score;
					return typeof overallScore === "number" ? overallScore : null;
				}),
			);

			const numericScores = scoreRows.filter((score): score is number => typeof score === "number");
			const combinedScore = numericScores.length > 0 ? numericScores.reduce((sum, value) => sum + value, 0) : null;

			return [student.id, { combinedScore, scoredAssignments: numericScores.length }] as const;
		}),
	);

	const scoreByStudentId = new Map(studentScoreEntries);
	const endangeredRankByStudentId = new Map(
		studentScoreEntries
			.filter(([, entry]) => entry.combinedScore != null)
			.sort((left, right) => {
				const scoreDelta = (left[1].combinedScore ?? Number.POSITIVE_INFINITY) - (right[1].combinedScore ?? Number.POSITIVE_INFINITY);
				if (scoreDelta !== 0) return scoreDelta;
				const scoredAssignmentDelta = left[1].scoredAssignments - right[1].scoredAssignments;
				if (scoredAssignmentDelta !== 0) return scoredAssignmentDelta;
				const leftStudent = students.find((student) => student.id === left[0]);
				const rightStudent = students.find((student) => student.id === right[0]);
				return (leftStudent?.full_name ?? "").localeCompare(rightStudent?.full_name ?? "");
			})
			.slice(0, 3)
			.map(([studentId], index) => [studentId, (index + 1) as 1 | 2 | 3]),
	);

	const selectedStudent =
		(selectedStudentId != null ? students.find((student) => student.id === selectedStudentId) : null) ?? students[0] ?? null;

	const studentItems = students.map((student) => {
		const studentRedoRows = redoAssignments
			.map((assignment) => ({ assignment, row: (reviewQueueByAssignment.get(assignment.id) ?? []).find((item) => item.student_id === student.id) ?? null }))
			.filter((entry) => entry.row != null);

		const liveRedoCount = studentRedoRows.filter((entry) => entry.assignment.status !== "closed").length;
		const closedRedoCount = studentRedoRows.filter((entry) => entry.assignment.status === "closed").length;
		const submittedCount = studentRedoRows.filter((entry) => (entry.row?.submitted_questions ?? 0) > 0).length;
		const scoring = scoreByStudentId.get(student.id) ?? { combinedScore: null, scoredAssignments: 0 };

		return {
			id: student.id,
			name: student.full_name,
			email: student.email,
			initials: initialsFor(student.full_name),
			statusLabel: submittedCount > 0 ? "Needs review" : liveRedoCount > 0 ? "Redo active" : closedRedoCount > 0 ? "Redo history" : "No redo",
			redoCountLabel: `${studentRedoRows.length} redo assignment${studentRedoRows.length === 1 ? "" : "s"}`,
			combinedScoreLabel: formatCombinedScoreLabel(scoring.combinedScore, scoring.scoredAssignments),
			note: studentNote(submittedCount, liveRedoCount, closedRedoCount),
			href: getDashboardTeacherClassroomHref(classroomId, student.id),
			selected: student.id === selectedStudent?.id,
			endangeredRank: endangeredRankByStudentId.get(student.id) ?? null,
		};
	});

	const selectedStudentRedoAssignments = selectedStudent
		? redoAssignments
				.map((assignment) => {
					const queueRow = (reviewQueueByAssignment.get(assignment.id) ?? []).find((item) => item.student_id === selectedStudent.id);
					if (!queueRow) return null;

					const latestActivity = queueRow.latest_submitted_at ?? queueRow.latest_reviewed_at;
					const summary = reviewSummaryByAssignment.get(assignment.id);

					return {
						id: assignment.id,
						title: assignment.title,
						statusLabel: assignment.status === "closed" ? "Closed" : queueStatusLabel(queueRow),
						statusTone: assignment.status === "closed" ? "success" : queueStatusTone(queueRow),
						dueLabel: `Due ${formatShortDate(assignment.due_at)}`,
						progressLabel: `${queueRow.reviewed_questions}/${queueRow.total_questions} reviewed`,
						nextStepLabel: queueRow.next_step_outcome ? `Next step: ${queueRow.next_step_outcome.replace(/_/g, " ")}` : "Next step still pending",
						note:
							(queueRow.submitted_questions ?? 0) > 0
								? `${queueRow.submitted_questions} question${queueRow.submitted_questions === 1 ? " is" : "s are"} waiting for review.`
								: summary && summary.reviewed > 0
									? `Latest activity ${formatRelativeTime(latestActivity)}.`
									: assignment.status === "closed"
										? "Closed redo assignment kept here for this student’s history."
										: "Assigned redo work with no submission yet.",
						 href: getAssignmentReviewHref("teacher", assignment.id),
					};
				})
				.filter((item): item is TeacherClassroomRedoAssignmentItem => item != null)
				.sort((left, right) => {
					const leftClosed = left.statusLabel === "Closed" ? 1 : 0;
					const rightClosed = right.statusLabel === "Closed" ? 1 : 0;
					return leftClosed - rightClosed || left.title.localeCompare(right.title);
				})
		: [];

	const liveRedoCount = redoAssignments.filter((assignment) => assignment.status !== "closed").length;
	const classroomNeedsReviewCount = redoAssignments.reduce((total, assignment) => {
		const rows = reviewQueueByAssignment.get(assignment.id) ?? [];
		return total + rows.filter((row) => row.submitted_questions > 0).length;
	}, 0);

	return {
		shell: buildTeacherShell(classroom.name, classroom.code, classrooms.length, classroomNeedsReviewCount),
		classroom: {
			id: classroom.id,
			name: classroom.name,
			description: classroom.description?.trim() || "Track each student’s follow-up work and individual redo assignments from here.",
			codeLabel: classroom.code ? `Invite code ${classroom.code}` : "Invite code not set",
			stats: [
				{ label: teacherDashboardLabels.classroomDetail.students, value: `${students.length}`, note: students.length === 0 ? "No students in this classroom yet" : "Roster ready for drilldown" },
				{ label: teacherDashboardLabels.classroomDetail.redoAssignments, value: `${redoAssignments.length}`, note: `${liveRedoCount} live · ${redoAssignments.length - liveRedoCount} closed` },
				{ label: teacherDashboardLabels.classroomDetail.waitingReview, value: `${classroomNeedsReviewCount}`, note: classroomNeedsReviewCount > 0 ? "Student-specific redo work needs attention" : "Nothing urgent in redo follow-up" },
			],
		},
		students: {
			title: teacherDashboardLabels.classroomDetail.students,
			description: "Pick a student to inspect their individual redo assignments in this classroom.",
			items: studentItems,
		},
		selectedStudent: {
			id: selectedStudent?.id ?? null,
			name: selectedStudent?.full_name ?? null,
			email: selectedStudent?.email ?? null,
			note: selectedStudent
				? selectedStudentRedoAssignments.length > 0
					? `${selectedStudentRedoAssignments.length} redo assignment${selectedStudentRedoAssignments.length === 1 ? "" : "s"} tied to this student in ${classroom.name}.`
					: "This student does not have any individual redo assignments in this classroom yet."
				: "Select a student to view their individual redo assignments.",
		},
		redoAssignments: {
			title: selectedStudent ? `${selectedStudent.full_name} redo assignments` : "Student redo assignments",
			description: selectedStudent
				? "These are the individual redo assignments created specifically for the selected student."
				: "Select a student from the roster to inspect their individual redo assignments.",
			items: selectedStudentRedoAssignments,
		},
	};
};
