import { apiFetchJson } from "../../../lib/api";
import type {
	ApiAssignment,
	ApiClassroom,
	ApiGenerateQuestionsResponse,
	ApiListResponse,
	ApiQuestion,
	ApiReviewSummary,
	ApiStudent,
} from "../../../lib/api-types";
import { teacherDashboardLabels } from "../../../content/dashboard-labels";
import { getDashboardHomeHref } from "../../../lib/routes";
import {
	FIXED_PASS_THRESHOLD,
	buildAssignmentItem,
	buildEmptyReviewSummary,
	formatShortDate,
	isIndividualRedoAssignment,
	mapSetupQuestion,
	sortDueSoonest,
	sortNeedsAttention,
} from "./dashboard-teacher-assignments.helpers";
import type {
	DashboardTeacherAssignmentsFocusData,
	GenerateTeacherQuestionsInput,
	GenerateTeacherQuestionsResult,
	MixedGenerationInput,
	TeacherAssignmentSetupData,
} from "./dashboard-teacher-assignments.types";

export type {
	DashboardTeacherAssignmentsFocusData,
	GenerateTeacherQuestionsInput,
	GenerateTeacherQuestionsResult,
	MixedGenerationInput,
	TeacherAssignmentSetupData,
	TeacherAssignmentSetupQuestion,
} from "./dashboard-teacher-assignments.types";

export { formatDetailedDate, formatDateTimeLocalInput, isIndividualRedoAssignment } from "./dashboard-teacher-assignments.helpers";

type CreateTeacherAssignmentInput = {
	teacherId: number;
	classroomId: number;
	title: string;
	instructions: string;
	dueAt: string;
	selectedQuestionIds: number[];
	assignedStudentIds?: number[];
	mixedGeneration?: MixedGenerationInput | null;
};

export const getTeacherAssignmentSetupData = async (teacherId: number): Promise<TeacherAssignmentSetupData> => {
	const [classroomsResponse, questionsResponse] = await Promise.all([
		apiFetchJson<ApiListResponse<ApiClassroom>>(`/api/teachers/${teacherId}/classrooms`),
		apiFetchJson<ApiListResponse<ApiQuestion>>(`/api/teachers/${teacherId}/questions`),
	]);

	const classrooms = classroomsResponse.data;
	const questions = questionsResponse.data;
	const studentsByClassroomEntries = await Promise.all(
		classrooms.map(async (classroom) => [classroom.id, (await apiFetchJson<ApiListResponse<ApiStudent>>(`/api/classrooms/${classroom.id}/students`)).data] as const),
	);
	const studentsByClassroom = new Map(studentsByClassroomEntries);

	return {
		classrooms: classrooms
			.slice()
			.sort((left, right) => left.name.localeCompare(right.name))
			.map((classroom) => {
				const studentCount = (studentsByClassroom.get(classroom.id) ?? []).length;
				return {
					id: classroom.id,
					name: classroom.name,
					description: classroom.description?.trim() || "No class note added yet.",
					studentCountLabel: `${studentCount} student${studentCount === 1 ? "" : "s"}`,
				};
			}),
		questions: questions
			.slice()
			.sort((left, right) => {
				const rightTime = new Date(right.updated_at ?? right.created_at ?? 0).getTime();
				const leftTime = new Date(left.updated_at ?? left.created_at ?? 0).getTime();
				return rightTime - leftTime;
			})
			.map(mapSetupQuestion),
	};
};

export const generateTeacherQuestions = async (input: GenerateTeacherQuestionsInput): Promise<GenerateTeacherQuestionsResult> => {
	const response = await apiFetchJson<ApiGenerateQuestionsResponse>("/api/questions/generate", {
		method: "POST",
		body: JSON.stringify({
			topic: input.topic,
			difficulty: input.difficulty,
			count: input.count,
			seed: typeof input.seed === "number" ? input.seed : undefined,
			status: input.status,
			source: input.source,
		}),
		parseErrorMessage: true,
	});

	return {
		seed: response.seed,
		count: response.count,
		questions: response.data.map((item) => mapSetupQuestion(item.question)),
		generatedQuestionIds: response.data.map((item) => item.question.id),
	};
};

export const createTeacherAssignment = async (input: CreateTeacherAssignmentInput) => {
	const title = input.title.trim();
	const instructions = input.instructions.trim();
	const dueDate = input.dueAt ? new Date(input.dueAt) : null;
	const mixedGeneration = input.mixedGeneration ?? null;

	if (!title) throw new Error("Add an assignment title before creating it.");
	if (!input.classroomId) throw new Error("Choose a classroom for this assignment.");
	if (dueDate && Number.isNaN(dueDate.getTime())) throw new Error("Pick a valid due date and time.");
	if (!mixedGeneration && input.selectedQuestionIds.length === 0) {
		throw new Error("Select at least one question before creating homework.");
	}

	if (mixedGeneration) {
		if (!mixedGeneration.primaryTopic.trim()) {
			throw new Error("Choose a primary topic for personalized generation.");
		}

		if (!mixedGeneration.primaryDifficulty) {
			throw new Error("Choose a primary difficulty for personalized generation.");
		}

		if (!Number.isInteger(mixedGeneration.totalQuestions) || mixedGeneration.totalQuestions < 1) {
			throw new Error("Choose a total personalized question count greater than 0.");
		}
	}

	const assignment = await apiFetchJson<ApiAssignment>("/api/assignments", {
		method: "POST",
		body: JSON.stringify({
			classroom_id: input.classroomId,
			teacher_id: input.teacherId,
			title,
			instructions: instructions || null,
			pass_threshold: FIXED_PASS_THRESHOLD,
			status: "assigned",
			due_at: dueDate ? dueDate.toISOString() : null,
			published_at: new Date().toISOString(),
		}),
		parseErrorMessage: true,
	});

	if (!mixedGeneration && input.selectedQuestionIds.length > 0) {
		await Promise.all(
			input.selectedQuestionIds.map((questionId, index) =>
				apiFetchJson(`/api/assignments/${assignment.id}/questions`, {
					method: "POST",
					body: JSON.stringify({ question_id: questionId, position: index + 1 }),
					parseErrorMessage: true,
				}),
			),
		);
	}

	const studentIds =
		input.assignedStudentIds && input.assignedStudentIds.length > 0
			? Array.from(new Set(input.assignedStudentIds))
			: (await apiFetchJson<ApiListResponse<ApiStudent>>(`/api/classrooms/${input.classroomId}/students`)).data.map((student) => student.id);

	await Promise.all(
		studentIds.map((studentId) =>
			apiFetchJson(`/api/assignments/${assignment.id}/students`, {
				method: "POST",
				body: JSON.stringify(
					mixedGeneration
						? {
								student_id: studentId,
								mixed_generation: {
									primary_topic: mixedGeneration.primaryTopic,
									primary_difficulty: mixedGeneration.primaryDifficulty,
									total_questions: mixedGeneration.totalQuestions,
									personalized_ratio: mixedGeneration.personalizedRatio,
									seed: mixedGeneration.seed,
									personalized_difficulty: mixedGeneration.personalizedDifficulty,
									subject: mixedGeneration.subject?.trim() || undefined,
									question_status: mixedGeneration.questionStatus,
									question_source: mixedGeneration.questionSource?.trim() || undefined,
								},
						  }
						: { student_id: studentId },
				),
				parseErrorMessage: true,
			}),
		),
	);

	return assignment;
};

export const getDashboardTeacherAssignmentsFocusData = async (teacherId: number): Promise<DashboardTeacherAssignmentsFocusData> => {
	const [assignmentsResponse, classroomsResponse] = await Promise.all([
		apiFetchJson<ApiListResponse<ApiAssignment>>(`/api/teachers/${teacherId}/assignments`),
		apiFetchJson<ApiListResponse<ApiClassroom>>(`/api/teachers/${teacherId}/classrooms`),
	]);

	const assignments = assignmentsResponse.data;
	const classrooms = classroomsResponse.data;

	const [studentsByClassroomEntries, summaryEntries] = await Promise.all([
		Promise.all(classrooms.map(async (classroom) => [classroom.id, (await apiFetchJson<ApiListResponse<ApiStudent>>(`/api/classrooms/${classroom.id}/students`)).data] as const)),
		Promise.all(assignments.map(async (assignment) => [assignment.id, await apiFetchJson<ApiReviewSummary>(`/api/assignments/${assignment.id}/review-summary`)] as const)),
	]);

	const classroomById = new Map(classrooms.map((classroom) => [classroom.id, classroom]));
	const studentsByClassroom = new Map(studentsByClassroomEntries);
	const summaries = new Map(summaryEntries);

	const liveAssignments = assignments.filter((assignment) => assignment.status === "assigned" || assignment.status === "draft");
	const individualRedoAssignments = liveAssignments.filter(isIndividualRedoAssignment);
	const liveClassroomAssignments = liveAssignments.filter((assignment) => !isIndividualRedoAssignment(assignment));
	const closedAssignments = assignments.filter(
		(assignment) => assignment.status === "closed" && !isIndividualRedoAssignment(assignment),
	);
	const needsReviewAssignments = liveAssignments.filter((assignment) => (summaries.get(assignment.id)?.submitted ?? 0) > 0);

	const totalStudents = new Set(
		Array.from(studentsByClassroom.values())
			.flat()
			.map((student) => student.id),
	).size;
	const submittedCount = assignments.reduce((total, assignment) => total + (summaries.get(assignment.id)?.submitted ?? 0), 0);
	const totalAssigned = assignments.reduce((total, assignment) => total + (summaries.get(assignment.id)?.total_assigned ?? 0), 0);
	const totalReviewed = assignments.reduce((total, assignment) => total + (summaries.get(assignment.id)?.reviewed ?? 0), 0);
	const reviewCoverage = totalAssigned > 0 ? Math.round((totalReviewed / totalAssigned) * 100) : 0;
	const nextDue = liveClassroomAssignments.slice().sort(sortDueSoonest).find((assignment) => assignment.due_at);

	const mapGroupItems = (entries: ApiAssignment[]) =>
		entries.map((assignment) =>
			buildAssignmentItem(
				assignment,
				classroomById.get(assignment.classroom_id),
				summaries.get(assignment.id) ?? buildEmptyReviewSummary(assignment.id),
				(studentsByClassroom.get(assignment.classroom_id) ?? []).length,
			),
		);

	return {
		stats: [
			{ label: teacherDashboardLabels.assignments.needsReview, value: `${submittedCount}`, note: "Fresh submissions waiting for feedback" },
			{
				label: teacherDashboardLabels.assignments.liveAssignments,
				value: `${liveClassroomAssignments.length}`,
				note:
					individualRedoAssignments.length > 0
						? `${individualRedoAssignments.length} student redo assignment${individualRedoAssignments.length === 1 ? "" : "s"} hidden from the main list`
						: `${closedAssignments.length} closed assignment${closedAssignments.length === 1 ? "" : "s"} archived separately`,
			},
			{ label: teacherDashboardLabels.assignments.studentsCovered, value: `${totalStudents}`, note: `${classrooms.length} classroom${classrooms.length === 1 ? "" : "s"} connected` },
			{ label: teacherDashboardLabels.assignments.reviewCoverage, value: `${reviewCoverage}%`, note: nextDue ? `${teacherDashboardLabels.common.nextDue} ${formatShortDate(nextDue.due_at)}` : "No live due date scheduled" },
		],
		groups: [
			{
				title: "Needs attention now",
				description: "Homework with submitted work already waiting in the teacher review queue.",
				items: mapGroupItems(needsReviewAssignments.slice().sort((left, right) => sortNeedsAttention(left, right, summaries))),
			},
			{
				title: "Live homework",
				description: "Published classroom homework that students can already see or are actively working through.",
				items: mapGroupItems(liveClassroomAssignments.slice().sort((left, right) => sortNeedsAttention(left, right, summaries))),
			},
			{
				title: "Closed",
				description: "Past assignments that remain useful for reflection and reference.",
				items: mapGroupItems(closedAssignments.slice().sort(sortDueSoonest)),
			},
		].filter((group) => group.items.length > 0),
		coachNote: {
			title: submittedCount > 0 ? "Review queue is active" : "Assignment set looks steady",
			description:
				submittedCount > 0
					? `You have ${submittedCount} submission${submittedCount === 1 ? "" : "s"} waiting. Start with the review queue, then come back here to manage live homework.`
					: "Use this page to keep live homework and closed work easy to scan so setup and follow-up stay easier to manage.",
			ctaLabel: submittedCount > 0 ? "Open dashboard review queue" : "Back to teaching overview",
			ctaHref: getDashboardHomeHref("teacher"),
		},
	};
};
