<script lang="ts">
	import type { StudentGrade, StudentAverages, SubjectAverage } from '$lib/features/grades/api/studentGrades';
	import { fetchMyGrades, fetchMyAverages } from '$lib/features/grades/api/studentGrades';
	import {
		setRevealMode,
		isGradeNew,
		markGradesSeen,
		isGradeRevealed,
		revealGrade,
		isDiscoverMode
	} from '$lib/features/grades/stores/gradePreferences.svelte';
	import SkeletonList from '$lib/components/atoms/Skeleton/SkeletonList.svelte';

	let grades: StudentGrade[] = $state([]);
	let averages: StudentAverages | null = $state(null);
	let isLoading = $state(true);
	let error: string | null = $state(null);
	let selectedSubjectId: string | null = $state(null);

	// Group grades by subject
	let subjectGroups = $derived.by(() => {
		const map = new Map<string, { subjectName: string; grades: StudentGrade[] }>();
		for (const g of grades) {
			const key = g.subjectId;
			const existing = map.get(key);
			if (existing) {
				existing.grades.push(g);
			} else {
				map.set(key, { subjectName: g.subjectName ?? 'Matière inconnue', grades: [g] });
			}
		}
		return map;
	});

	// Find average for a subject
	function subjectAverage(subjectId: string): SubjectAverage | undefined {
		return averages?.subjectAverages.find((a) => a.subjectId === subjectId);
	}

	// Filtered grades for selected subject detail
	let detailGrades = $derived.by(() => {
		if (!selectedSubjectId) return [];
		return grades.filter((g) => g.subjectId === selectedSubjectId);
	});

	let detailSubjectName = $derived.by(() => {
		if (!selectedSubjectId) return '';
		return subjectGroups.get(selectedSubjectId)?.subjectName ?? '';
	});

	let detailAverage = $derived.by(() => {
		if (!selectedSubjectId) return undefined;
		return subjectAverage(selectedSubjectId);
	});

	// Color based on grade value (green ≥ 14, orange 10-14, red < 10, on /20 scale)
	function gradeColor(value: number | null, scale: number): string {
		if (value === null || scale <= 0) return '#6b7280';
		const normalized = (value / scale) * 20;
		if (normalized >= 14) return '#22c55e';
		if (normalized >= 10) return '#f59e0b';
		return '#ef4444';
	}

	function formatDate(dateStr: string): string {
		const d = new Date(dateStr + 'T00:00:00');
		return d.toLocaleDateString('fr-FR', { day: 'numeric', month: 'short', year: 'numeric' });
	}

	function handleReveal(gradeId: string) {
		revealGrade(gradeId);
	}

	function toggleDiscoverMode() {
		const newMode = isDiscoverMode() ? 'immediate' : 'discover';
		setRevealMode(newMode);
	}

	let seenTimerId: number | null = null;

	$effect(() => {
		loadData();
		return () => {
			if (seenTimerId !== null) window.clearTimeout(seenTimerId);
		};
	});

	async function loadData() {
		try {
			isLoading = true;
			error = null;

			const [gradesData, averagesData] = await Promise.all([fetchMyGrades(), fetchMyAverages()]);

			grades = gradesData;
			averages = averagesData;

			// Mark all loaded grades as seen (for "Nouveau" badge)
			const ids = gradesData.map((g) => g.id);
			// Delay marking to let the badge show briefly
			seenTimerId = window.setTimeout(() => markGradesSeen(ids), 3000);
		} catch (e) {
			error = e instanceof Error ? e.message : 'Erreur inconnue';
		} finally {
			isLoading = false;
		}
	}

	function openSubjectDetail(subjectId: string) {
		selectedSubjectId = subjectId;
	}

	function closeDetail() {
		selectedSubjectId = null;
	}

	function handleOverlayClick(e: MouseEvent) {
		if (e.target === e.currentTarget) closeDetail();
	}

	function handleKeydown(e: KeyboardEvent) {
		if (e.key === 'Escape' && selectedSubjectId) closeDetail();
	}
</script>

<svelte:window onkeydown={handleKeydown} />

<div class="student-grades">
	<header class="page-header">
		<div class="header-top">
			<h1>Mes notes</h1>
			<label class="discover-toggle">
				<input type="checkbox" checked={isDiscoverMode()} onchange={toggleDiscoverMode} />
				<span class="toggle-label">Mode découverte</span>
			</label>
		</div>

		{#if averages?.generalAverage != null}
			<div class="general-average">
				<span class="avg-label">Moyenne générale</span>
				<span class="avg-value" style:color={gradeColor(averages.generalAverage, 20)}>
					{averages.generalAverage.toFixed(1)}/20
				</span>
			</div>
		{/if}
	</header>

	{#if error}
		<div class="error-banner" role="alert">
			<p>{error}</p>
			<button onclick={() => (error = null)}>Fermer</button>
		</div>
	{/if}

	{#if isLoading}
		<SkeletonList items={5} message="Chargement des notes..." />
	{:else if grades.length === 0}
		<div class="empty-state">
			<p>Aucune note publiée pour le moment.</p>
		</div>
	{:else}
		<!-- Subject averages summary -->
		{#if averages && averages.subjectAverages.length > 0}
			<section class="averages-section">
				<h2>Moyennes par matière</h2>
				<div class="averages-grid">
					{#each averages.subjectAverages as avg}
						<button
							class="average-card"
							onclick={() => openSubjectDetail(avg.subjectId)}
						>
							<span class="avg-subject">{avg.subjectName ?? 'Matière'}</span>
							<span class="avg-score" style:color={gradeColor(avg.average, 20)}>
								{avg.average.toFixed(1)}
							</span>
							<span class="avg-count">{avg.gradeCount} note{avg.gradeCount > 1 ? 's' : ''}</span>
						</button>
					{/each}
				</div>
			</section>
		{/if}

		<!-- Recent grades -->
		<section class="recent-section">
			<h2>Dernières notes</h2>
			<ul class="grades-list">
				{#each grades as grade (grade.id)}
					{@const discover = isDiscoverMode() && !isGradeRevealed(grade.id)}
					{@const isNew = isGradeNew(grade.id)}
					<li class="grade-card">
						<div class="grade-card-header">
							<button class="grade-subject-btn" onclick={() => openSubjectDetail(grade.subjectId)}>{grade.subjectName ?? 'Matière'}</button>
							<span class="grade-date">{formatDate(grade.evaluationDate)}</span>
							{#if isNew}
								<span class="badge-new">Nouveau</span>
							{/if}
						</div>
						<div class="grade-card-body">
							<span class="grade-eval-title">{grade.evaluationTitle}</span>
							{#if discover}
								<button class="reveal-btn" onclick={() => handleReveal(grade.id)}>
									<span class="reveal-blur">??/{grade.gradeScale}</span>
									<span class="reveal-hint">Cliquer pour révéler</span>
								</button>
							{:else if grade.status === 'graded' && grade.value != null}
								<span class="grade-value" style:color={gradeColor(grade.value, grade.gradeScale)}>
									{grade.value}/{grade.gradeScale}
								</span>
							{:else if grade.status === 'absent'}
								<span class="grade-status absent">Absent</span>
							{:else if grade.status === 'dispensed'}
								<span class="grade-status dispensed">Dispensé</span>
							{/if}
						</div>
						{#if !discover && grade.classAverage != null}
							<div class="grade-card-stats">
								<span>Moy. classe : {grade.classAverage.toFixed(1)}</span>
								{#if grade.classMin != null && grade.classMax != null}
									<span>Min : {grade.classMin.toFixed(1)} / Max : {grade.classMax.toFixed(1)}</span>
								{/if}
							</div>
						{/if}
						{#if !discover && grade.appreciation}
							<p class="grade-appreciation">{grade.appreciation}</p>
						{/if}
						<div class="grade-card-meta">
							<span class="grade-coeff">Coeff. {grade.coefficient}</span>
						</div>
					</li>
				{/each}
			</ul>
		</section>
	{/if}
</div>

<!-- Subject detail modal -->
{#if selectedSubjectId}
	<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
	<div class="modal-overlay" onclick={handleOverlayClick} role="presentation">
		<div class="modal" role="dialog" aria-modal="true" aria-label="Détail matière {detailSubjectName}">
			<div class="modal-header">
				<h2>{detailSubjectName}</h2>
				<button class="modal-close" onclick={closeDetail} aria-label="Fermer">&times;</button>
			</div>
			{#if detailAverage}
				<div class="modal-average">
					<span class="avg-label">Moyenne</span>
					<span class="avg-value" style:color={gradeColor(detailAverage.average, 20)}>
						{detailAverage.average.toFixed(1)}/20
					</span>
				</div>
			{/if}
			<ul class="detail-list">
				{#each detailGrades as grade (grade.id)}
					{@const discover = isDiscoverMode() && !isGradeRevealed(grade.id)}
					<li class="detail-item">
						<div class="detail-header">
							<span class="detail-title">{grade.evaluationTitle}</span>
							<span class="detail-date">{formatDate(grade.evaluationDate)}</span>
						</div>
						<div class="detail-body">
							{#if discover}
								<button class="reveal-btn" onclick={() => handleReveal(grade.id)}>
									<span class="reveal-blur">??/{grade.gradeScale}</span>
									<span class="reveal-hint">Cliquer pour révéler</span>
								</button>
							{:else if grade.status === 'graded' && grade.value != null}
								<span class="grade-value" style:color={gradeColor(grade.value, grade.gradeScale)}>
									{grade.value}/{grade.gradeScale}
								</span>
							{:else if grade.status === 'absent'}
								<span class="grade-status absent">Absent</span>
							{:else if grade.status === 'dispensed'}
								<span class="grade-status dispensed">Dispensé</span>
							{/if}
							<span class="grade-coeff">Coeff. {grade.coefficient}</span>
						</div>
						{#if !discover && grade.classAverage != null}
							<div class="grade-card-stats">
								<span>Moy. classe : {grade.classAverage.toFixed(1)}</span>
								{#if grade.classMin != null && grade.classMax != null}
									<span>Min : {grade.classMin.toFixed(1)} / Max : {grade.classMax.toFixed(1)}</span>
								{/if}
							</div>
						{/if}
						{#if !discover && grade.appreciation}
							<p class="grade-appreciation">{grade.appreciation}</p>
						{/if}
					</li>
				{/each}
			</ul>
		</div>
	</div>
{/if}

<style>
	.student-grades {
		max-width: 64rem;
		margin: 0 auto;
		padding: 1rem;
		display: flex;
		flex-direction: column;
		gap: 1.5rem;
	}

	.page-header {
		display: flex;
		flex-direction: column;
		gap: 0.75rem;
	}

	.header-top {
		display: flex;
		justify-content: space-between;
		align-items: center;
		flex-wrap: wrap;
		gap: 0.5rem;
	}

	.page-header h1 {
		margin: 0;
		font-size: 1.5rem;
		font-weight: 700;
		color: #1f2937;
	}

	.discover-toggle {
		display: flex;
		align-items: center;
		gap: 0.5rem;
		cursor: pointer;
		font-size: 0.875rem;
		color: #6b7280;
	}

	.discover-toggle input {
		accent-color: #8b5cf6;
	}

	.toggle-label {
		user-select: none;
	}

	.general-average {
		display: flex;
		align-items: center;
		gap: 0.75rem;
		padding: 1rem 1.25rem;
		background: #f0fdf4;
		border: 1px solid #bbf7d0;
		border-radius: 0.75rem;
	}

	.avg-label {
		font-size: 0.875rem;
		color: #6b7280;
	}

	.avg-value {
		font-size: 1.5rem;
		font-weight: 700;
	}

	.error-banner {
		display: flex;
		justify-content: space-between;
		align-items: center;
		padding: 0.75rem 1rem;
		background: #fef2f2;
		border: 1px solid #fecaca;
		border-radius: 0.5rem;
		color: #991b1b;
	}

	.error-banner p {
		margin: 0;
	}

	.error-banner button {
		background: none;
		border: none;
		color: #991b1b;
		cursor: pointer;
		font-weight: 500;
	}

	.empty-state {
		text-align: center;
		padding: 3rem 1rem;
		color: #6b7280;
	}

	/* Averages section */
	.averages-section h2,
	.recent-section h2 {
		font-size: 1.125rem;
		font-weight: 600;
		color: #1f2937;
		margin: 0 0 0.75rem;
	}

	.averages-grid {
		display: grid;
		gap: 0.75rem;
		grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
	}

	.average-card {
		display: flex;
		flex-direction: column;
		align-items: center;
		gap: 0.25rem;
		padding: 1rem;
		background: white;
		border: 1px solid #e5e7eb;
		border-radius: 0.75rem;
		cursor: pointer;
		transition:
			box-shadow 0.15s,
			border-color 0.15s;
		font: inherit;
	}

	.average-card:hover {
		border-color: #3b82f6;
		box-shadow: 0 2px 8px rgba(59, 130, 246, 0.15);
	}

	.avg-subject {
		font-size: 0.75rem;
		font-weight: 600;
		color: #6b7280;
		text-transform: uppercase;
	}

	.avg-score {
		font-size: 1.75rem;
		font-weight: 700;
	}

	.avg-count {
		font-size: 0.75rem;
		color: #9ca3af;
	}

	/* Grade cards */
	.grades-list {
		list-style: none;
		margin: 0;
		padding: 0;
		display: flex;
		flex-direction: column;
		gap: 0.75rem;
	}

	.grade-card {
		padding: 1rem;
		background: white;
		border: 1px solid #e5e7eb;
		border-radius: 0.75rem;
	}

	.grade-card-header {
		display: flex;
		align-items: center;
		gap: 0.5rem;
		margin-bottom: 0.5rem;
	}

	.grade-subject-btn {
		font-size: 0.75rem;
		font-weight: 600;
		color: #3b82f6;
		text-transform: uppercase;
		background: none;
		border: none;
		cursor: pointer;
		padding: 0;
		font: inherit;
		text-decoration: underline;
		text-decoration-color: transparent;
		transition: text-decoration-color 0.15s;
	}

	.grade-subject-btn:hover {
		text-decoration-color: #3b82f6;
	}

	.grade-date {
		font-size: 0.75rem;
		color: #9ca3af;
		margin-left: auto;
	}

	.badge-new {
		font-size: 0.625rem;
		padding: 0.125rem 0.5rem;
		background: #eff6ff;
		color: #2563eb;
		border-radius: 1rem;
		font-weight: 600;
		text-transform: uppercase;
	}

	.grade-card-body {
		display: flex;
		justify-content: space-between;
		align-items: center;
		gap: 0.5rem;
	}

	.grade-eval-title {
		font-weight: 500;
		color: #1f2937;
	}

	.grade-value {
		font-weight: 700;
		font-size: 1.125rem;
		white-space: nowrap;
	}

	.grade-status {
		font-size: 0.875rem;
		font-weight: 500;
	}

	.grade-status.absent {
		color: #f59e0b;
	}

	.grade-status.dispensed {
		color: #6b7280;
	}

	.grade-card-stats {
		display: flex;
		gap: 1rem;
		font-size: 0.75rem;
		color: #9ca3af;
		margin-top: 0.5rem;
	}

	.grade-appreciation {
		margin: 0.5rem 0 0;
		font-size: 0.875rem;
		color: #4b5563;
		font-style: italic;
	}

	.grade-card-meta {
		margin-top: 0.5rem;
	}

	.grade-coeff {
		font-size: 0.75rem;
		color: #9ca3af;
	}

	/* Reveal button */
	.reveal-btn {
		display: flex;
		flex-direction: column;
		align-items: center;
		gap: 0.125rem;
		background: #f3f4f6;
		border: 1px dashed #d1d5db;
		border-radius: 0.5rem;
		padding: 0.5rem 1rem;
		cursor: pointer;
		transition: background 0.15s;
	}

	.reveal-btn:hover {
		background: #e5e7eb;
	}

	.reveal-blur {
		font-weight: 700;
		font-size: 1.125rem;
		color: #9ca3af;
		filter: blur(4px);
	}

	.reveal-hint {
		font-size: 0.625rem;
		color: #6b7280;
	}

	/* Modal */
	.modal-overlay {
		position: fixed;
		inset: 0;
		background: rgba(0, 0, 0, 0.5);
		display: flex;
		align-items: center;
		justify-content: center;
		z-index: 50;
		padding: 1rem;
	}

	.modal {
		position: relative;
		background: white;
		border-radius: 0.75rem;
		padding: 1.5rem;
		max-width: 40rem;
		width: 100%;
		max-height: 80vh;
		overflow-y: auto;
		box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
	}

	.modal-header {
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin-bottom: 1rem;
	}

	.modal-header h2 {
		margin: 0;
		font-size: 1.25rem;
		font-weight: 700;
		color: #1f2937;
	}

	.modal-close {
		background: none;
		border: none;
		font-size: 1.5rem;
		color: #6b7280;
		cursor: pointer;
		line-height: 1;
		padding: 0.25rem;
	}

	.modal-close:hover {
		color: #1f2937;
	}

	.modal-average {
		display: flex;
		align-items: center;
		gap: 0.75rem;
		padding: 0.75rem 1rem;
		background: #f0fdf4;
		border: 1px solid #bbf7d0;
		border-radius: 0.5rem;
		margin-bottom: 1rem;
	}

	.detail-list {
		list-style: none;
		margin: 0;
		padding: 0;
		display: flex;
		flex-direction: column;
		gap: 0.75rem;
	}

	.detail-item {
		padding: 0.75rem;
		background: #f9fafb;
		border-radius: 0.5rem;
	}

	.detail-header {
		display: flex;
		justify-content: space-between;
		align-items: center;
		margin-bottom: 0.25rem;
	}

	.detail-title {
		font-weight: 500;
		color: #1f2937;
	}

	.detail-date {
		font-size: 0.75rem;
		color: #9ca3af;
	}

	.detail-body {
		display: flex;
		justify-content: space-between;
		align-items: center;
		gap: 0.5rem;
	}
</style>
