import { getAssignmentReviewHref, getAssignmentWorkHref } from "../../../lib/routes";
import type { ApiAssignment, ApiAssignmentStudentQuestionDetail } from "../../../lib/api-types";
import { studentDashboardLabels } from "../../../content/dashboard-labels";
import type { AccentTone, AssignmentCard, PerformanceTone, UsageItem } from "../shared/dashboard-types";

type DerivedAssignment = {
	assignment: ApiAssignment;
	questions: ApiAssignmentStudentQuestionDetail[];
	status: "NOT_STARTED" | "IN_PROGRESS" | "SUBMITTED";
	answeredCount: number;
	reviewedCount: number;
	topic: string;
	lastTouchedAt: string | null;
};

type TopicAggregate = {
	label: string;
	total: number;
	answered: number;
	reviewed: number;
	completion: number;
};

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

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

export const initialsFor = (name: string) =>
	name
		.split(" ")
		.filter(Boolean)
		.slice(0, 2)
		.map((part) => part[0])
		.join("")
		.toUpperCase();

export const formatAssignmentBadge = (title: string) => {
	const leadSegment = title.split(/[—-]/)[0]?.trim() ?? title.trim();
	const tokens = leadSegment.match(/[A-Za-z]+|\d+/g) ?? [];

	if (tokens.length === 0) return "HW";

	const firstWord = tokens.find((token) => /^[A-Za-z]+$/.test(token));
	const firstNumber = tokens.find((token) => /^\d+$/.test(token));

	if (firstWord && firstNumber) {
		return `${firstWord[0]?.toUpperCase() ?? "H"}${firstNumber}`;
	}

	if (tokens.length === 1) {
		return tokens[0]!.slice(0, 2).toUpperCase();
	}

	return tokens
		.slice(0, 2)
		.map((token) => (/^\d+$/.test(token) ? token : token[0]?.toUpperCase() ?? ""))
		.join("")
		.toUpperCase();
};

export const formatAssignmentShortTitle = (title: string, fallback = "Task") => {
	const leadSegment = title.split(/[—-]/)[0]?.trim() ?? title.trim();
	return leadSegment || fallback;
};

export const formatRelativeTime = (value: string | null) => {
	if (!value) return "No recent updates";

	const deltaMs = Date.now() - new Date(value).getTime();
	const deltaMinutes = Math.max(0, Math.round(deltaMs / (1000 * 60)));

	if (deltaMinutes < 60) return `${deltaMinutes || 1}m ago`;
	const deltaHours = Math.round(deltaMinutes / 60);
	if (deltaHours < 24) return `${deltaHours}h ago`;
	const deltaDays = Math.round(deltaHours / 24);
	if (deltaDays < 7) return `${deltaDays}d ago`;
	return formatShortDate(value);
};

export const daysUntil = (value: string | null) => {
	if (!value) return null;
	const msPerDay = 1000 * 60 * 60 * 24;
	return Math.ceil((new Date(value).getTime() - Date.now()) / msPerDay);
};

export const formatDueCountdown = (days: number | null, mode: "compact" | "labelled" = "compact") => {
	if (days === null) return studentDashboardLabels.quickStats.noDeadline;
	if (days < 0) {
		return mode === "labelled" ? `${Math.abs(days)}d ${studentDashboardLabels.quickStats.overdue.toLowerCase()}` : studentDashboardLabels.quickStats.overdue;
	}
	if (days === 0) return studentDashboardLabels.quickStats.dueToday;
	return mode === "labelled" ? `${days}d left` : `${days}d`;
};

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

const deriveAssignmentStatus = (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 ((total > 0 && reviewed === total) || assignment.status === "closed") return "SUBMITTED" as const;
	return "IN_PROGRESS" as const;
};

export const toneAt = <T extends string>(tones: T[], index: number) => tones[index % tones.length];

export const sortByDueDate = (left: DerivedAssignment, right: DerivedAssignment) => {
	const leftTime = left.assignment.due_at ? new Date(left.assignment.due_at).getTime() : Number.POSITIVE_INFINITY;
	const rightTime = right.assignment.due_at ? new Date(right.assignment.due_at).getTime() : Number.POSITIVE_INFINITY;
	return leftTime - rightTime;
};

export const buildDerivedAssignments = (
	assignments: ApiAssignment[],
	questionsByAssignment: Map<number, ApiAssignmentStudentQuestionDetail[]>,
) =>
	assignments.map((assignment) => {
		const questions = questionsByAssignment.get(assignment.id) ?? [];
		const answeredCount = questions.filter((question) => question.answer_id).length;
		const reviewedCount = questions.filter((question) => question.answer_status === "reviewed").length;
		const lastTouchedAt =
			questions
				.flatMap((question) => [question.reviewed_at, question.submitted_at, question.answer_updated_at, question.answer_created_at])
				.filter((value): value is string => Boolean(value))
				.sort((left, right) => new Date(right).getTime() - new Date(left).getTime())[0] ?? assignment.updated_at;

		return {
			assignment,
			questions,
			status: deriveAssignmentStatus(assignment, questions),
			answeredCount,
			reviewedCount,
			topic: extractTopic(assignment, questions),
			lastTouchedAt,
		};
	});

export const buildTopicAggregates = (assignments: DerivedAssignment[]) => {
	const topicMap = new Map<string, TopicAggregate>();

	for (const assignment of assignments) {
		for (const question of assignment.questions) {
			const key = question.subject || assignment.topic || "Assignment";
			const current = topicMap.get(key) ?? {
				label: key,
				total: 0,
				answered: 0,
				reviewed: 0,
				completion: 0,
			};

			current.total += 1;
			if (question.answer_id) current.answered += 1;
			if (question.answer_status === "reviewed") current.reviewed += 1;
			current.completion = current.total === 0 ? 0 : Math.round((current.reviewed / current.total) * 100);
			topicMap.set(key, current);
		}
	}

	return [...topicMap.values()].sort((left, right) => left.completion - right.completion || right.total - left.total);
};

export const buildAssignmentCards = (assignments: DerivedAssignment[]): AssignmentCard[] => {
	const tones: AccentTone[] = ["yellow", "blue", "teal", "pink"];

	return assignments
		.slice()
		.sort((left, right) => {
			const statusWeight = {
				IN_PROGRESS: 0,
				NOT_STARTED: 1,
				SUBMITTED: 2,
			} as const;
			return statusWeight[left.status] - statusWeight[right.status] || sortByDueDate(left, right);
		})
		.slice(0, 3)
		.map((item, index) => ({
			title: item.assignment.title,
			badge: formatAssignmentBadge(item.assignment.title),
			lessons:
				item.status === "SUBMITTED"
					? `${item.reviewedCount}/${item.questions.length || 0} reviewed · revisit feedback`
					: item.status === "IN_PROGRESS"
						? `${item.answeredCount}/${item.questions.length || 0} answered · due ${formatShortDate(item.assignment.due_at)}`
						: `${item.questions.length || 0} questions · starts with ${item.topic}`,
			accent: toneAt(tones, index),
			cta: item.status === "SUBMITTED" ? "Open review" : item.status === "IN_PROGRESS" ? "Resume work" : "Start now",
			href: item.status === "SUBMITTED" ? getAssignmentReviewHref("student", item.assignment.id) : getAssignmentWorkHref(item.assignment.id),
		}));
};

export const buildProgressSeries = (assignments: DerivedAssignment[]) => {
	const recent = assignments
		.slice()
		.sort((left, right) => new Date(left.assignment.created_at).getTime() - new Date(right.assignment.created_at).getTime())
		.slice(-5);

	if (recent.length === 0) {
		return {
			labels: ["Plan", "Start", "Work", "Review", "Finish"],
			points: [20, 32, 44, 58, 66],
		};
	}

	return {
		labels: recent.map((item) => item.assignment.title.split(" ")[0]),
		points: recent.map((item) => {
			const total = item.questions.length || 1;
			const progress = Math.round((item.reviewedCount / total) * 100);
			return Math.max(12, Math.min(100, progress));
		}),
	};
};

export const buildUsageItems = (totalQuestions: number, totalReviewed: number, totalAnswered: number, remainingCount: number): UsageItem[] => [
	{ label: studentDashboardLabels.insights.reviewed, value: totalQuestions > 0 ? Math.round((totalReviewed / totalQuestions) * 100) : 0, tone: "teal" },
	{ label: studentDashboardLabels.insights.answered, value: totalQuestions > 0 ? Math.round((totalAnswered / totalQuestions) * 100) : 0, tone: "blue" },
	{ label: studentDashboardLabels.insights.remaining, value: totalQuestions > 0 ? Math.round((remainingCount / totalQuestions) * 100) : 0, tone: "yellow" },
];

export const masteryTones: PerformanceTone[] = ["blue", "purple", "teal", "pink", "yellow"];
