<script lang="ts">
	import { goto } from '$app/navigation';
	import { page } from '$app/state';
	import { getApiBaseUrl } from '$lib/api/config';
	import { authenticatedFetch, getAuthenticatedUserId } from '$lib/auth';
	import Pagination from '$lib/components/molecules/Pagination/Pagination.svelte';
	import ExceptionRequestModal from '$lib/components/molecules/ExceptionRequestModal/ExceptionRequestModal.svelte';
	import RuleBlockedModal from '$lib/components/molecules/RuleBlockedModal/RuleBlockedModal.svelte';
	import FileUpload from '$lib/components/molecules/FileUpload/FileUpload.svelte';
	import RichTextEditor from '$lib/components/molecules/RichTextEditor/RichTextEditor.svelte';
	import SearchInput from '$lib/components/molecules/SearchInput/SearchInput.svelte';
	import { untrack } from 'svelte';

	interface Homework {
		id: string;
		classId: string;
		subjectId: string;
		teacherId: string;
		title: string;
		description: string | null;
		dueDate: string;
		status: string;
		className: string | null;
		subjectName: string | null;
		hasRuleOverride: boolean;
		hasRuleException?: boolean;
		ruleExceptionJustification?: string | null;
		ruleExceptionRuleType?: string | null;
		createdAt: string;
		updatedAt: string;
	}

	interface HomeworkAttachmentFile {
		id: string;
		filename: string;
		fileSize: number;
		mimeType: string;
	}

	interface RuleWarning {
		ruleType: string;
		message: string;
		params: Record<string, unknown>;
	}

	interface TeacherAssignment {
		id: string;
		classId: string;
		subjectId: string;
		status: string;
	}

	interface SchoolClass {
		id: string;
		name: string;
	}

	interface Subject {
		id: string;
		name: string;
		code: string;
	}

	// State
	let homeworks = $state<Homework[]>([]);
	let assignments = $state<TeacherAssignment[]>([]);
	let classes = $state<SchoolClass[]>([]);
	let subjects = $state<Subject[]>([]);
	let isLoading = $state(true);
	let error = $state<string | null>(null);

	// Pagination & Search
	let currentPage = $state(Number(page.url.searchParams.get('page')) || 1);
	let searchTerm = $state(page.url.searchParams.get('search') ?? '');
	let totalItems = $state(0);
	const itemsPerPage = 30;
	let totalPages = $derived(Math.ceil(totalItems / itemsPerPage));

	// Create modal
	let showCreateModal = $state(false);
	let newClassId = $state('');
	let newSubjectId = $state('');
	let newTitle = $state('');
	let newDescription = $state('');
	let newDueDate = $state('');
	let isSubmitting = $state(false);
	let newPendingFiles = $state<File[]>([]);

	// Attachments
	let editAttachments = $state<HomeworkAttachmentFile[]>([]);

	// Edit modal
	let showEditModal = $state(false);
	let editHomework = $state<Homework | null>(null);
	let editTitle = $state('');
	let editDescription = $state('');
	let editDueDate = $state('');
	let isUpdating = $state(false);

	// Delete modal
	let showDeleteModal = $state(false);
	let homeworkToDelete = $state<Homework | null>(null);
	let isDeleting = $state(false);

	// Duplicate modal
	let showDuplicateModal = $state(false);
	let homeworkToDuplicate = $state<Homework | null>(null);
	let selectedTargetClassIds = $state<string[]>([]);
	let dueDatesByClass = $state<Record<string, string>>({});
	let isDuplicating = $state(false);
	let duplicateError = $state<string | null>(null);
	let duplicateValidationResults = $state<Array<{ classId: string; valid: boolean; error: string | null }>>([]);
	let duplicateWarnings = $state<Array<{ classId: string; warning: string }>>([]);

	// Rule warning modal (soft mode)
	let showRuleWarningModal = $state(false);
	let ruleWarnings = $state<RuleWarning[]>([]);
	let ruleConformMinDate = $state('');

	// Rule blocked modal (hard mode)
	let showRuleBlockedModal = $state(false);
	let ruleBlockedWarnings = $state<RuleWarning[]>([]);
	let ruleBlockedSuggestedDates = $state<string[]>([]);

	// Exception justification viewing
	let showJustificationModal = $state(false);
	let justificationHomework = $state<Homework | null>(null);

	// Exception request modal
	let showExceptionModal = $state(false);
	let exceptionWarnings = $state<RuleWarning[]>([]);
	let isSubmittingException = $state(false);

	// Inline date validation for hard mode
	let dueDateError = $state<string | null>(null);

	// Class filter
	let filterClassId = $state(page.url.searchParams.get('classId') ?? '');

	// Derived: available subjects for selected class
	let availableSubjectsForCreate = $derived.by(() => {
		if (!newClassId) return [];
		const assignedSubjectIds = assignments
			.filter((a) => a.classId === newClassId && a.status === 'active')
			.map((a) => a.subjectId);
		return subjects.filter((s) => assignedSubjectIds.includes(s.id));
	});

	// Derived: minimum due date (tomorrow)
	let minDueDate = $derived.by(() => {
		const tomorrow = new Date();
		tomorrow.setDate(tomorrow.getDate() + 1);
		const y = tomorrow.getFullYear();
		const m = String(tomorrow.getMonth() + 1).padStart(2, '0');
		const d = String(tomorrow.getDate()).padStart(2, '0');
		return `${y}-${m}-${d}`;
	});

	// Load on mount
	$effect(() => {
		untrack(() => loadAll());
	});

	function extractCollection<T>(data: Record<string, unknown>): T[] {
		const members = data['hydra:member'] ?? data['member'];
		if (Array.isArray(members)) return members as T[];
		if (Array.isArray(data)) return data as T[];
		return [];
	}

	async function loadAssignments() {
		const userId = await getAuthenticatedUserId();
		if (!userId) return;
		const apiUrl = getApiBaseUrl();
		const res = await authenticatedFetch(`${apiUrl}/teachers/${userId}/assignments`);
		if (!res.ok) throw new Error('Erreur lors du chargement des affectations');
		const data = await res.json();
		assignments = extractCollection<TeacherAssignment>(data);
	}

	async function loadAll() {
		try {
			isLoading = true;
			error = null;
			const apiUrl = getApiBaseUrl();

			// classesRes/subjectsRes are used below; loadAssignments & loadHomeworks
			// apply side-effects internally and their results are intentionally ignored
			const [classesRes, subjectsRes] = await Promise.all([
				authenticatedFetch(`${apiUrl}/classes?itemsPerPage=100`),
				authenticatedFetch(`${apiUrl}/subjects?itemsPerPage=100`),
				loadAssignments().catch((e) => {
					error = e instanceof Error ? e.message : 'Erreur lors du chargement des affectations';
				}),
				loadHomeworks().catch((e) => {
					homeworks = [];
					totalItems = 0;
					error = e instanceof Error ? e.message : 'Erreur inconnue';
				}),
			]);

			if (!classesRes.ok) throw new Error('Erreur lors du chargement des classes');
			if (!subjectsRes.ok) throw new Error('Erreur lors du chargement des matières');

			const [classesData, subjectsData] = await Promise.all([
				classesRes.json(),
				subjectsRes.json(),
			]);

			classes = extractCollection<SchoolClass>(classesData);
			subjects = extractCollection<Subject>(subjectsData);
		} catch (e) {
			error = e instanceof Error ? e.message : 'Erreur inconnue';
		} finally {
			isLoading = false;
		}
	}

	let loadAbortController: AbortController | null = null;

	async function loadHomeworks() {
		loadAbortController?.abort();
		const controller = new AbortController();
		loadAbortController = controller;

		try {
			const apiUrl = getApiBaseUrl();
			const params = new URLSearchParams();
			params.set('page', String(currentPage));
			params.set('itemsPerPage', String(itemsPerPage));
			if (searchTerm) params.set('search', searchTerm);
			if (filterClassId) params.set('classId', filterClassId);

			const response = await authenticatedFetch(`${apiUrl}/homework?${params.toString()}`, {
				signal: controller.signal,
			});

			if (controller.signal.aborted) return;

			if (!response.ok) {
				throw new Error('Erreur lors du chargement des devoirs');
			}

			const data = await response.json();
			homeworks = extractCollection<Homework>(data);
			totalItems = (data as Record<string, unknown>)['hydra:totalItems'] as number ?? (data as Record<string, unknown>)['totalItems'] as number ?? homeworks.length;
		} catch (e) {
			if (e instanceof DOMException && e.name === 'AbortError') return;
			throw e;
		}
	}

	function updateUrl() {
		const params = new URLSearchParams();
		if (currentPage > 1) params.set('page', String(currentPage));
		if (searchTerm) params.set('search', searchTerm);
		if (filterClassId) params.set('classId', filterClassId);
		const query = params.toString();
		goto(`?${query}`, { replaceState: true, noScroll: true, keepFocus: true });
	}

	function handleSearch(value: string) {
		searchTerm = value;
		currentPage = 1;
		updateUrl();
		loadHomeworks().catch((e) => {
			error = e instanceof Error ? e.message : 'Erreur inconnue';
		});
	}

	function handlePageChange(newPage: number) {
		currentPage = newPage;
		updateUrl();
		loadHomeworks().catch((e) => {
			error = e instanceof Error ? e.message : 'Erreur inconnue';
		});
	}

	function getClassName(classId: string): string {
		return classes.find((c) => c.id === classId)?.name ?? classId;
	}

	function getSubjectName(subjectId: string): string {
		return subjects.find((s) => s.id === subjectId)?.name ?? subjectId;
	}

	function formatDate(dateStr: string): string {
		return new Date(dateStr).toLocaleDateString('fr-FR', {
			day: 'numeric',
			month: 'long',
			year: 'numeric',
		});
	}

	function isOverdue(dueDate: string): boolean {
		const due = new Date(dueDate);
		const today = new Date();
		today.setHours(0, 0, 0, 0);
		due.setHours(0, 0, 0, 0);
		return due < today;
	}

	// Available classes = classes the teacher is assigned to
	let availableClasses = $derived.by(() => {
		const assignedClassIds = [...new Set(assignments.filter((a) => a.status === 'active').map((a) => a.classId))];
		return classes.filter((c) => assignedClassIds.includes(c.id));
	});

	// Available target classes for duplication (same subject, exclude source class)
	let availableTargetClasses = $derived.by(() => {
		if (!homeworkToDuplicate) return [];
		const sourceSubjectId = homeworkToDuplicate.subjectId;
		const sourceClassId = homeworkToDuplicate.classId;
		const assignedClassIds = assignments
			.filter((a) => a.status === 'active' && a.subjectId === sourceSubjectId)
			.map((a) => a.classId);
		return classes.filter((c) => assignedClassIds.includes(c.id) && c.id !== sourceClassId);
	});

	function handleClassFilter(newClassId: string) {
		filterClassId = newClassId;
		currentPage = 1;
		updateUrl();
		loadHomeworks().catch((e) => {
			error = e instanceof Error ? e.message : 'Erreur inconnue';
		});
	}

	// --- Create ---
	function openCreateModal() {
		showCreateModal = true;
		newClassId = '';
		newSubjectId = '';
		newTitle = '';
		newDescription = '';
		newDueDate = '';
		newPendingFiles = [];
		ruleConformMinDate = '';
		dueDateError = null;
	}

	function closeCreateModal() {
		showCreateModal = false;
	}

	async function handleCreate(acknowledgeWarning = false) {
		if (!newClassId || !newSubjectId || !newTitle.trim() || !newDueDate) return;
		dueDateError = validateDueDateLocally(newDueDate);
		if (dueDateError) return;

		try {
			isSubmitting = true;
			error = null;
			const apiUrl = getApiBaseUrl();
			const response = await authenticatedFetch(`${apiUrl}/homework`, {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({
					classId: newClassId,
					subjectId: newSubjectId,
					title: newTitle.trim(),
					description: newDescription.trim() || null,
					dueDate: newDueDate,
					acknowledgeWarning,
				}),
			});

			if (response.status === 422) {
				const data = await response.json().catch(() => null);
				if (data?.type === 'homework_rules_blocked' && Array.isArray(data.warnings)) {
					ruleBlockedWarnings = data.warnings;
					ruleBlockedSuggestedDates = Array.isArray(data.suggestedDates) ? data.suggestedDates : [];
					showCreateModal = false;
					showRuleBlockedModal = true;
					return;
				}
			}

			if (response.status === 409) {
				const data = await response.json().catch(() => null);
				if (data?.type === 'homework_rules_warning' && Array.isArray(data.warnings)) {
					ruleWarnings = data.warnings;
					showCreateModal = false;
					showRuleWarningModal = true;
					return;
				}
			}

			if (!response.ok) {
				const errorData = await response.json().catch(() => null);
				const msg =
					errorData?.['hydra:description'] ??
					errorData?.message ??
					errorData?.detail ??
					`Erreur lors de la création (${response.status})`;
				throw new Error(msg);
			}

			// Upload pending files if any
			if (newPendingFiles.length > 0) {
				const created = await response.json().catch(() => null);
				const homeworkId = created?.id;
				if (homeworkId) {
					for (const file of newPendingFiles) {
						try {
							await uploadAttachment(homeworkId, file);
						} catch {
							// Best effort — file upload failure doesn't block creation
						}
					}
				}
				newPendingFiles = [];
			}

			closeCreateModal();
			showRuleWarningModal = false;
			ruleWarnings = [];
			showRuleBlockedModal = false;
			ruleBlockedWarnings = [];
			ruleBlockedSuggestedDates = [];
			await loadHomeworks();
		} catch (e) {
			error = e instanceof Error ? e.message : 'Erreur lors de la création';
		} finally {
			isSubmitting = false;
		}
	}

	function handleContinueDespiteWarning() {
		showRuleWarningModal = false;
		handleCreate(true);
	}

	function computeConformMinDate(warnings: RuleWarning[]): string {
		let minDate = new Date();
		minDate.setDate(minDate.getDate() + 1); // au moins demain

		for (const w of warnings) {
			if (w.ruleType === 'minimum_delay' && typeof w.params['days'] === 'number') {
				const ruleMin = new Date();
				ruleMin.setDate(ruleMin.getDate() + (w.params['days'] as number));
				if (ruleMin > minDate) minDate = ruleMin;
			}
			if (w.ruleType === 'no_monday_after') {
				// Si le lundi est interdit (deadline dépassée), proposer mardi
				// car le problème ne concerne que les devoirs pour lundi
				const nextTuesday = new Date();
				nextTuesday.setDate(nextTuesday.getDate() + ((9 - nextTuesday.getDay()) % 7 || 7));
				if (nextTuesday > minDate) minDate = nextTuesday;
			}
		}

		// Sauter les weekends
		const day = minDate.getDay();
		if (day === 0) minDate.setDate(minDate.getDate() + 1);
		if (day === 6) minDate.setDate(minDate.getDate() + 2);

		const y = minDate.getFullYear();
		const m = String(minDate.getMonth() + 1).padStart(2, '0');
		const d = String(minDate.getDate()).padStart(2, '0');
		return `${y}-${m}-${d}`;
	}

	function handleModifyDate() {
		ruleConformMinDate = computeConformMinDate(ruleWarnings);
		showRuleWarningModal = false;
		showCreateModal = true;
		newDueDate = ruleConformMinDate;
	}

	function validateDueDateLocally(dateStr: string): string | null {
		if (!dateStr) return null;
		const date = new Date(dateStr + 'T00:00:00');
		const day = date.getDay();
		if (day === 0 || day === 6) {
			return 'Les devoirs ne peuvent pas être fixés un weekend.';
		}
		if (ruleConformMinDate && dateStr < ruleConformMinDate) {
			return 'Cette date ne respecte pas les règles de l\'établissement. Choisissez une date ultérieure.';
		}
		return null;
	}

	function handleDueDateChange(dateStr: string) {
		newDueDate = dateStr;
		dueDateError = validateDueDateLocally(dateStr);
	}

	function handleBlockedSelectDate(date: string) {
		showRuleBlockedModal = false;
		ruleBlockedWarnings = [];
		ruleBlockedSuggestedDates = [];
		ruleConformMinDate = date;
		newDueDate = date;
		showCreateModal = true;
	}

	function handleRequestException() {
		exceptionWarnings = ruleBlockedWarnings;
		showRuleBlockedModal = false;
		showExceptionModal = true;
	}

	async function handleExceptionSubmit(justification: string, ruleTypes: string[]) {
		if (!newClassId || !newSubjectId || !newTitle.trim() || !newDueDate) return;

		try {
			isSubmittingException = true;
			error = null;
			const apiUrl = getApiBaseUrl();
			const response = await authenticatedFetch(`${apiUrl}/homework/with-exception`, {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({
					classId: newClassId,
					subjectId: newSubjectId,
					title: newTitle.trim(),
					description: newDescription.trim() || null,
					dueDate: newDueDate,
					justification,
					ruleTypes,
				}),
			});

			if (!response.ok) {
				const errorData = await response.json().catch(() => null);
				const msg =
					errorData?.['hydra:description'] ??
					errorData?.message ??
					errorData?.detail ??
					`Erreur lors de la création avec exception (${response.status})`;
				throw new Error(msg);
			}

			showExceptionModal = false;
			exceptionWarnings = [];
			ruleBlockedWarnings = [];
			ruleBlockedSuggestedDates = [];
			await loadHomeworks();
		} catch (e) {
			error = e instanceof Error ? e.message : 'Erreur lors de la création avec exception';
		} finally {
			isSubmittingException = false;
		}
	}

	function handleBlockedClose() {
		const firstSuggested = ruleBlockedSuggestedDates[0];
		const conformDate = firstSuggested ?? computeConformMinDate(ruleBlockedWarnings);
		showRuleBlockedModal = false;
		ruleBlockedWarnings = [];
		ruleBlockedSuggestedDates = [];
		ruleConformMinDate = conformDate;
		newDueDate = conformDate;
		showCreateModal = true;
	}

	// --- Attachments ---
	async function uploadAttachment(homeworkId: string, file: File): Promise<HomeworkAttachmentFile> {
		const apiUrl = getApiBaseUrl();
		const formData = new window.FormData();
		formData.append('file', file);

		const response = await authenticatedFetch(`${apiUrl}/homework/${homeworkId}/attachments`, {
			method: 'POST',
			body: formData,
		});

		if (!response.ok) {
			const errorData = await response.json().catch(() => null);
			throw new Error(errorData?.detail ?? 'Erreur lors de l\'envoi du fichier.');
		}

		return response.json() as Promise<HomeworkAttachmentFile>;
	}

	async function deleteAttachment(homeworkId: string, attachmentId: string): Promise<void> {
		const apiUrl = getApiBaseUrl();
		const response = await authenticatedFetch(`${apiUrl}/homework/${homeworkId}/attachments/${attachmentId}`, {
			method: 'DELETE',
		});

		if (!response.ok) {
			throw new Error('Erreur lors de la suppression du fichier.');
		}
	}

	async function fetchAttachments(homeworkId: string): Promise<HomeworkAttachmentFile[]> {
		const apiUrl = getApiBaseUrl();
		const response = await authenticatedFetch(`${apiUrl}/homework/${homeworkId}/attachments`);

		if (!response.ok) return [];

		const data = await response.json();
		return (data as HomeworkAttachmentFile[]) ?? [];
	}

	// --- Edit ---
	async function openEditModal(hw: Homework) {
		editHomework = hw;
		editTitle = hw.title;
		editDescription = hw.description ?? '';
		editDueDate = hw.dueDate;
		editAttachments = [];
		showEditModal = true;

		// Charger les pièces jointes existantes en arrière-plan
		editAttachments = await fetchAttachments(hw.id);
	}

	function closeEditModal() {
		showEditModal = false;
		editHomework = null;
		editAttachments = [];
	}

	async function handleUpdate() {
		if (!editHomework || !editTitle.trim() || !editDueDate) return;

		try {
			isUpdating = true;
			error = null;
			const apiUrl = getApiBaseUrl();
			const response = await authenticatedFetch(`${apiUrl}/homework/${editHomework.id}`, {
				method: 'PATCH',
				headers: { 'Content-Type': 'application/merge-patch+json' },
				body: JSON.stringify({
					title: editTitle.trim(),
					description: editDescription.trim() || null,
					dueDate: editDueDate,
				}),
			});

			if (!response.ok) {
				const errorData = await response.json().catch(() => null);
				const msg =
					errorData?.['hydra:description'] ??
					errorData?.message ??
					errorData?.detail ??
					`Erreur lors de la modification (${response.status})`;
				throw new Error(msg);
			}

			closeEditModal();
			await loadHomeworks();
		} catch (e) {
			error = e instanceof Error ? e.message : 'Erreur lors de la modification';
		} finally {
			isUpdating = false;
		}
	}

	// --- Duplicate ---
	function openDuplicateModal(hw: Homework) {
		homeworkToDuplicate = hw;
		selectedTargetClassIds = [];
		dueDatesByClass = {};
		duplicateError = null;
		duplicateValidationResults = [];
		duplicateWarnings = [];
		showDuplicateModal = true;
	}

	function closeDuplicateModal() {
		showDuplicateModal = false;
		homeworkToDuplicate = null;
	}

	function toggleTargetClass(classId: string) {
		if (selectedTargetClassIds.includes(classId)) {
			selectedTargetClassIds = selectedTargetClassIds.filter((id) => id !== classId);
			const { [classId]: _, ...rest } = dueDatesByClass;
			dueDatesByClass = rest;
		} else {
			selectedTargetClassIds = [...selectedTargetClassIds, classId];
		}
	}

	async function handleDuplicate() {
		if (!homeworkToDuplicate || selectedTargetClassIds.length === 0) return;

		try {
			isDuplicating = true;
			duplicateError = null;
			duplicateValidationResults = [];
			const apiUrl = getApiBaseUrl();

			const dueDates: Record<string, string> = {};
			for (const classId of selectedTargetClassIds) {
				if (dueDatesByClass[classId]) {
					dueDates[classId] = dueDatesByClass[classId];
				}
			}

			const response = await authenticatedFetch(`${apiUrl}/homework/${homeworkToDuplicate.id}/duplicate`, {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({
					targetClassIds: selectedTargetClassIds,
					dueDates: Object.keys(dueDates).length > 0 ? dueDates : undefined,
				}),
			});

			if (!response.ok) {
				const errorData = await response.json().catch(() => null);
				if (errorData?.results) {
					duplicateValidationResults = errorData.results;
					duplicateError = 'Certaines classes ne passent pas la validation.';
					return;
				}
				throw new Error(
					errorData?.['hydra:description'] ??
						errorData?.error ??
						errorData?.message ??
						`Erreur lors de la duplication (${response.status})`,
				);
			}

			const responseData = await response.json();
			if (responseData?.warnings?.length > 0) {
				duplicateWarnings = responseData.warnings;
			}

			closeDuplicateModal();
			await loadHomeworks();
		} catch (e) {
			duplicateError = e instanceof Error ? e.message : 'Erreur lors de la duplication';
		} finally {
			isDuplicating = false;
		}
	}

	// --- Delete ---
	function openDeleteModal(hw: Homework) {
		homeworkToDelete = hw;
		showDeleteModal = true;
	}

	function closeDeleteModal() {
		showDeleteModal = false;
		homeworkToDelete = null;
	}

	async function handleDelete() {
		if (!homeworkToDelete) return;

		try {
			isDeleting = true;
			error = null;
			const apiUrl = getApiBaseUrl();
			const response = await authenticatedFetch(`${apiUrl}/homework/${homeworkToDelete.id}`, {
				method: 'DELETE',
			});

			if (!response.ok) {
				const errorData = await response.json().catch(() => null);
				const msg =
					errorData?.['hydra:description'] ??
					errorData?.message ??
					errorData?.detail ??
					`Erreur lors de la suppression (${response.status})`;
				throw new Error(msg);
			}

			closeDeleteModal();
			await loadHomeworks();
		} catch (e) {
			error = e instanceof Error ? e.message : 'Erreur lors de la suppression';
		} finally {
			isDeleting = false;
		}
	}
</script>

<svelte:head>
	<title>Mes devoirs - Classeo</title>
</svelte:head>

<div class="homework-page">
	<header class="page-header">
		<div class="header-content">
			<h1>Mes devoirs</h1>
			<p class="subtitle">Créez et gérez les devoirs pour vos classes</p>
		</div>
		<button class="btn-primary" onclick={openCreateModal} disabled={availableClasses.length === 0}>
			<span class="btn-icon">+</span>
			Nouveau devoir
		</button>
	</header>

	{#if error}
		<div class="alert alert-error">
			<span class="alert-icon">&#9888;</span>
			{error}
			<button class="alert-close" onclick={() => (error = null)}>&times;</button>
		</div>
	{/if}

	{#if duplicateWarnings.length > 0}
		<div class="alert alert-warning">
			<span class="alert-icon">&#9888;</span>
			<div>
				<strong>Duplication effectuée avec avertissements :</strong>
				<ul class="warning-list">
					{#each duplicateWarnings as w}
						<li>{getClassName(w.classId)} : {w.warning}</li>
					{/each}
				</ul>
			</div>
			<button class="alert-close" onclick={() => (duplicateWarnings = [])}>&times;</button>
		</div>
	{/if}

	<div class="filters-row">
		<SearchInput value={searchTerm} onSearch={handleSearch} placeholder="Rechercher par titre..." />
		<div class="class-filter">
			<select
				value={filterClassId}
				aria-label="Filtrer par classe"
				onchange={(e) => handleClassFilter((e.target as HTMLSelectElement).value)}
			>
				<option value="">Toutes les classes</option>
				{#each availableClasses as cls (cls.id)}
					<option value={cls.id}>{cls.name}</option>
				{/each}
			</select>
		</div>
	</div>

	{#if isLoading}
		<div class="loading-state" aria-live="polite" role="status">
			<div class="spinner"></div>
			<p>Chargement des devoirs...</p>
		</div>
	{:else if homeworks.length === 0}
		<div class="empty-state">
			<span class="empty-icon">&#128218;</span>
			{#if searchTerm}
				<h2>Aucun résultat</h2>
				<p>Aucun devoir ne correspond à votre recherche</p>
				<button class="btn-secondary" onclick={() => handleSearch('')}>Effacer la recherche</button>
			{:else}
				<h2>Aucun devoir</h2>
				<p>Commencez par créer votre premier devoir</p>
				<button class="btn-primary" onclick={openCreateModal} disabled={availableClasses.length === 0}>
					Créer un devoir
				</button>
			{/if}
		</div>
	{:else}
		<div class="homework-list">
			{#each homeworks as hw (hw.id)}
				<div class="homework-card" class:overdue={isOverdue(hw.dueDate)}>
					<div class="homework-header">
						<h3 class="homework-title">{hw.title}</h3>
						<div class="homework-badges">
							{#if hw.hasRuleException}
								<button
									type="button"
									class="badge-rule-exception"
									title="Créé avec une exception aux règles — cliquer pour voir la justification"
									onclick={() => { justificationHomework = hw; showJustificationModal = true; }}
								>&#9888; Exception</button>
							{:else if hw.hasRuleOverride}
								<span class="badge-rule-override" title="Créé malgré un avertissement de règle">&#9888;</span>
							{/if}
							<span class="homework-status" class:status-published={hw.status === 'published'} class:status-deleted={hw.status === 'deleted'}>
								{hw.status === 'published' ? 'Publié' : 'Supprimé'}
							</span>
						</div>
					</div>

					<div class="homework-meta">
						<span class="meta-item" title="Classe">
							<span class="meta-icon">&#127979;</span>
							{hw.className ?? getClassName(hw.classId)}
						</span>
						<span class="meta-item" title="Matière">
							<span class="meta-icon">&#128214;</span>
							{hw.subjectName ?? getSubjectName(hw.subjectId)}
						</span>
						<span class="meta-item" class:overdue-date={isOverdue(hw.dueDate)} title="Date d'échéance">
							<span class="meta-icon">&#128197;</span>
							{formatDate(hw.dueDate)}
						</span>
					</div>

					{#if hw.description}
						<div class="homework-description">{@html hw.description}</div>
					{/if}

					{#if hw.status === 'published'}
						<div class="homework-actions">
							<button class="btn-secondary btn-sm" onclick={() => openEditModal(hw)}>
								Modifier
							</button>
							<button class="btn-secondary btn-sm" onclick={() => openDuplicateModal(hw)}>
								Dupliquer
							</button>
							<button class="btn-danger btn-sm" onclick={() => openDeleteModal(hw)}>
								Supprimer
							</button>
						</div>
					{/if}
				</div>
			{/each}
		</div>
		<Pagination {currentPage} {totalPages} onPageChange={handlePageChange} />
	{/if}
</div>

<!-- Create Modal -->
{#if showCreateModal}
	<!-- svelte-ignore a11y_no_static_element_interactions -->
	<div class="modal-overlay" onclick={closeCreateModal} role="presentation">
		<div
			class="modal"
			role="dialog"
			aria-modal="true"
			aria-labelledby="create-modal-title"
			tabindex="-1"
			onclick={(e) => e.stopPropagation()}
			onkeydown={(e) => { if (e.key === 'Escape') closeCreateModal(); }}
		>
			<header class="modal-header">
				<h2 id="create-modal-title">Nouveau devoir</h2>
				<button class="modal-close" onclick={closeCreateModal} aria-label="Fermer">&times;</button>
			</header>

			<form
				class="modal-body"
				onsubmit={(e) => {
					e.preventDefault();
					handleCreate();
				}}
			>
				<div class="form-group">
					<label for="hw-class">Classe *</label>
					<select
						id="hw-class"
						bind:value={newClassId}
						required
						onchange={() => (newSubjectId = '')}
					>
						<option value="">-- Sélectionner une classe --</option>
						{#each availableClasses as cls (cls.id)}
							<option value={cls.id}>{cls.name}</option>
						{/each}
					</select>
				</div>

				<div class="form-group">
					<label for="hw-subject">Matière *</label>
					<select id="hw-subject" bind:value={newSubjectId} required disabled={!newClassId}>
						<option value="">-- Sélectionner une matière --</option>
						{#each availableSubjectsForCreate as subj (subj.id)}
							<option value={subj.id}>{subj.name}</option>
						{/each}
					</select>
					{#if newClassId && availableSubjectsForCreate.length === 0}
						<small class="form-hint form-hint-warning">Aucune matière affectée pour cette classe</small>
					{/if}
				</div>

				<div class="form-group">
					<label for="hw-title">Titre *</label>
					<input
						type="text"
						id="hw-title"
						bind:value={newTitle}
						placeholder="ex: Exercices chapitre 5"
						required
						minlength="2"
						maxlength="255"
					/>
				</div>

				<div class="form-group">
					<label>Description</label>
					<RichTextEditor
						content={newDescription}
						onUpdate={(html) => (newDescription = html)}
						placeholder="Consignes, pages à lire, liens utiles..."
						disabled={isSubmitting}
					/>
				</div>

				<div class="form-group">
					<label for="hw-due-date">Date d'échéance *</label>
					<input
						type="date"
						id="hw-due-date"
						value={newDueDate}
						oninput={(e) => handleDueDateChange((e.target as HTMLInputElement).value)}
						required
						min={ruleConformMinDate || minDueDate}
					/>
					{#if dueDateError}
						<small class="form-hint form-hint-error">{dueDateError}</small>
					{:else if ruleConformMinDate}
						<small class="form-hint form-hint-rule">
							Date minimale conforme aux règles : {new Date(ruleConformMinDate + 'T00:00:00').toLocaleDateString('fr-FR', { day: 'numeric', month: 'long', year: 'numeric' })}
						</small>
					{:else}
						<small class="form-hint">La date doit être au minimum demain, hors jours fériés et vacances</small>
					{/if}
				</div>

				<div class="form-group">
					<label>Pièces jointes</label>
					<FileUpload
						existingFiles={[]}
						onUpload={async (file) => {
							newPendingFiles = [...newPendingFiles, file];
							const pendingId = `pending-${file.name}-${file.size}`;
							return { id: pendingId, filename: file.name, fileSize: file.size, mimeType: file.type };
						}}
						onDelete={async (fileId) => {
							newPendingFiles = newPendingFiles.filter(
								(f) => `pending-${f.name}-${f.size}` !== fileId
							);
						}}
						disabled={isSubmitting}
					/>
					{#if newPendingFiles.length > 0}
						<small class="form-hint">Les fichiers seront envoyés après la création du devoir.</small>
					{/if}
				</div>

				<div class="modal-actions">
					<button type="button" class="btn-secondary" onclick={closeCreateModal} disabled={isSubmitting}>
						Annuler
					</button>
					<button
						type="submit"
						class="btn-primary"
						disabled={isSubmitting || !newClassId || !newSubjectId || !newTitle.trim() || !newDueDate}
					>
						{#if isSubmitting}
							Création...
						{:else}
							Créer le devoir
						{/if}
					</button>
				</div>
			</form>
		</div>
	</div>
{/if}

<!-- Edit Modal -->
{#if showEditModal && editHomework}
	<!-- svelte-ignore a11y_no_static_element_interactions -->
	<div class="modal-overlay" onclick={closeEditModal} role="presentation">
		<div
			class="modal"
			role="dialog"
			aria-modal="true"
			aria-labelledby="edit-modal-title"
			tabindex="-1"
			onclick={(e) => e.stopPropagation()}
			onkeydown={(e) => { if (e.key === 'Escape') closeEditModal(); }}
		>
			<header class="modal-header">
				<h2 id="edit-modal-title">Modifier le devoir</h2>
				<button class="modal-close" onclick={closeEditModal} aria-label="Fermer">&times;</button>
			</header>

			<form
				class="modal-body"
				onsubmit={(e) => {
					e.preventDefault();
					handleUpdate();
				}}
			>
				<div class="form-info">
					<span class="info-label">Classe :</span>
					<span>{editHomework.className ?? getClassName(editHomework.classId)}</span>
					<span class="info-label">Matière :</span>
					<span>{editHomework.subjectName ?? getSubjectName(editHomework.subjectId)}</span>
				</div>

				<div class="form-group">
					<label for="edit-title">Titre *</label>
					<input
						type="text"
						id="edit-title"
						bind:value={editTitle}
						required
						minlength="2"
						maxlength="255"
					/>
				</div>

				<div class="form-group">
					<label>Description</label>
					<RichTextEditor
						content={editDescription}
						onUpdate={(html) => (editDescription = html)}
						placeholder="Consignes, pages à lire, liens utiles..."
						disabled={isUpdating}
					/>
				</div>

				<div class="form-group">
					<label for="edit-due-date">Date d'échéance *</label>
					<input type="date" id="edit-due-date" bind:value={editDueDate} required min={minDueDate} />
				</div>

				{#if editHomework}
					<div class="form-group">
						<label>Pièces jointes</label>
						<FileUpload
							existingFiles={editAttachments}
							onUpload={(file) => uploadAttachment(editHomework!.id, file)}
							onDelete={(attachmentId) => deleteAttachment(editHomework!.id, attachmentId)}
							disabled={isUpdating}
						/>
					</div>
				{/if}

				<div class="modal-actions">
					<button type="button" class="btn-secondary" onclick={closeEditModal} disabled={isUpdating}>
						Annuler
					</button>
					<button
						type="submit"
						class="btn-primary"
						disabled={isUpdating || !editTitle.trim() || !editDueDate}
					>
						{#if isUpdating}
							Enregistrement...
						{:else}
							Enregistrer
						{/if}
					</button>
				</div>
			</form>
		</div>
	</div>
{/if}

<!-- Delete Confirmation Modal -->
{#if showDeleteModal && homeworkToDelete}
	<!-- svelte-ignore a11y_no_static_element_interactions -->
	<div class="modal-overlay" onclick={closeDeleteModal} role="presentation">
		<div
			class="modal modal-confirm"
			role="alertdialog"
			aria-modal="true"
			aria-labelledby="delete-modal-title"
			aria-describedby="delete-modal-description"
			tabindex="-1"
			onclick={(e) => e.stopPropagation()}
			onkeydown={(e) => { if (e.key === 'Escape') closeDeleteModal(); }}
		>
			<header class="modal-header modal-header-danger">
				<h2 id="delete-modal-title">Supprimer le devoir</h2>
				<button class="modal-close" onclick={closeDeleteModal} aria-label="Fermer">&times;</button>
			</header>

			<div class="modal-body">
				<p id="delete-modal-description">
					Êtes-vous sûr de vouloir supprimer le devoir <strong>{homeworkToDelete.title}</strong> ?
				</p>
				<p class="delete-warning">Les élèves et parents ne verront plus ce devoir.</p>
			</div>

			<div class="modal-actions">
				<button type="button" class="btn-secondary" onclick={closeDeleteModal} disabled={isDeleting}>
					Annuler
				</button>
				<button type="button" class="btn-danger" onclick={handleDelete} disabled={isDeleting}>
					{#if isDeleting}
						Suppression...
					{:else}
						Supprimer
					{/if}
				</button>
			</div>
		</div>
	</div>
{/if}

<!-- Duplicate Modal -->
{#if showDuplicateModal && homeworkToDuplicate}
	<!-- svelte-ignore a11y_no_static_element_interactions -->
	<div class="modal-overlay" onclick={closeDuplicateModal} role="presentation">
		<div
			class="modal"
			role="dialog"
			aria-modal="true"
			aria-labelledby="duplicate-modal-title"
			tabindex="-1"
			onclick={(e) => e.stopPropagation()}
			onkeydown={(e) => { if (e.key === 'Escape') closeDuplicateModal(); }}
		>
			<header class="modal-header">
				<h2 id="duplicate-modal-title">Dupliquer le devoir</h2>
				<button class="modal-close" onclick={closeDuplicateModal} aria-label="Fermer">&times;</button>
			</header>

			<div class="modal-body">
				<div class="form-info">
					<span class="info-label">Devoir :</span>
					<span>{homeworkToDuplicate.title}</span>
					<span class="info-label">Classe source :</span>
					<span>{homeworkToDuplicate.className ?? getClassName(homeworkToDuplicate.classId)}</span>
					<span class="info-label">Matière :</span>
					<span>{homeworkToDuplicate.subjectName ?? getSubjectName(homeworkToDuplicate.subjectId)}</span>
				</div>

				{#if duplicateError}
					<div class="alert alert-error" style="margin-bottom: 1rem;">
						<span class="alert-icon">&#9888;</span>
						{duplicateError}
					</div>
				{/if}

				{#if availableTargetClasses.length === 0}
					<p class="empty-target-classes">Aucune autre classe disponible pour cette matière.</p>
				{:else}
					<div class="form-group" role="group" aria-label="Classes cibles">
						<span class="field-label">Classes cibles *</span>
						<div class="checkbox-list">
							{#each availableTargetClasses as cls (cls.id)}
								{@const validationResult = duplicateValidationResults.find((r) => r.classId === cls.id)}
								<div class="checkbox-item" class:validation-error={validationResult && !validationResult.valid}>
									<label class="checkbox-label">
										<input
											type="checkbox"
											checked={selectedTargetClassIds.includes(cls.id)}
											onchange={() => toggleTargetClass(cls.id)}
										/>
										{cls.name}
									</label>
									{#if selectedTargetClassIds.includes(cls.id)}
										<div class="due-date-inline">
											<label for="due-{cls.id}">Date :</label>
											<input
												type="date"
												id="due-{cls.id}"
												value={dueDatesByClass[cls.id] ?? homeworkToDuplicate.dueDate}
												min={minDueDate}
												onchange={(e) => {
													dueDatesByClass = { ...dueDatesByClass, [cls.id]: (e.target as HTMLInputElement).value };
												}}
											/>
										</div>
									{/if}
									{#if validationResult && !validationResult.valid}
										<small class="form-hint form-hint-warning">{validationResult.error}</small>
									{/if}
								</div>
							{/each}
						</div>
					</div>
				{/if}

				<div class="modal-actions">
					<button type="button" class="btn-secondary" onclick={closeDuplicateModal} disabled={isDuplicating}>
						Annuler
					</button>
					<button
						type="button"
						class="btn-primary"
						onclick={handleDuplicate}
						disabled={isDuplicating || selectedTargetClassIds.length === 0}
					>
						{#if isDuplicating}
							Duplication...
						{:else}
							Dupliquer ({selectedTargetClassIds.length} classe{selectedTargetClassIds.length > 1 ? 's' : ''})
						{/if}
					</button>
				</div>
			</div>
		</div>
	</div>
{/if}

<!-- Rule Warning Modal -->
{#if showRuleWarningModal && ruleWarnings.length > 0}
	<!-- svelte-ignore a11y_no_static_element_interactions -->
	<div class="modal-overlay" role="presentation">
		<div
			class="modal modal-confirm"
			role="alertdialog"
			aria-modal="true"
			aria-labelledby="rule-warning-title"
			aria-describedby="rule-warning-description"
			tabindex="-1"
			onclick={(e) => e.stopPropagation()}
			onkeydown={(e) => { if (e.key === 'Escape') handleModifyDate(); }}
		>
			<header class="modal-header modal-header-warning">
				<h2 id="rule-warning-title">Avertissement</h2>
			</header>

			<div class="modal-body">
				<p id="rule-warning-description">
					Ce devoir ne respecte pas les règles configurées par votre établissement :
				</p>
				<ul class="rule-warning-list">
					{#each ruleWarnings as warning}
						<li class="rule-warning-item">
							<span class="rule-warning-icon">&#9888;</span>
							<span>{warning.message}</span>
						</li>
					{/each}
				</ul>
				<p class="rule-warning-notice">Votre choix sera enregistré.</p>
			</div>

			<div class="modal-actions">
				<button type="button" class="btn-secondary" onclick={handleModifyDate} disabled={isSubmitting}>
					Modifier la date
				</button>
				<button type="button" class="btn-primary" onclick={handleContinueDespiteWarning} disabled={isSubmitting}>
					{#if isSubmitting}
						Création...
					{:else}
						Continuer malgré tout
					{/if}
				</button>
			</div>
		</div>
	</div>
{/if}

<!-- Rule Blocked Modal (Hard Mode) -->
{#if showRuleBlockedModal && ruleBlockedWarnings.length > 0}
	<RuleBlockedModal
		warnings={ruleBlockedWarnings}
		suggestedDates={ruleBlockedSuggestedDates}
		onSelectDate={handleBlockedSelectDate}
		onClose={handleBlockedClose}
		onRequestException={handleRequestException}
	/>
{/if}

<!-- Exception Request Modal -->
{#if showExceptionModal && exceptionWarnings.length > 0}
	<ExceptionRequestModal
		warnings={exceptionWarnings}
		onSubmit={handleExceptionSubmit}
		onClose={() => {
			showExceptionModal = false;
			exceptionWarnings = [];
		}}
		isSubmitting={isSubmittingException}
	/>
{/if}

<!-- Justification Viewing Modal -->
{#if showJustificationModal && justificationHomework}
	<!-- svelte-ignore a11y_no_static_element_interactions -->
	<div class="modal-overlay" onclick={() => { showJustificationModal = false; justificationHomework = null; }} role="presentation">
		<div
			class="modal modal-confirm"
			role="dialog"
			aria-modal="true"
			aria-labelledby="justification-title"
			tabindex="-1"
			onclick={(e) => e.stopPropagation()}
			onkeydown={(e) => { if (e.key === 'Escape') { showJustificationModal = false; justificationHomework = null; } }}
		>
			<header class="modal-header modal-header-exception-view">
				<h2 id="justification-title">Exception aux règles</h2>
				<button class="modal-close" onclick={() => { showJustificationModal = false; justificationHomework = null; }} aria-label="Fermer">&times;</button>
			</header>

			<div class="modal-body">
				<div class="justification-info">
					<span class="justification-info-label">Devoir :</span>
					<span>{justificationHomework.title}</span>
					<span class="justification-info-label">Règle contournée :</span>
					<span>{justificationHomework.ruleExceptionRuleType ?? 'N/A'}</span>
				</div>
				<div class="justification-content">
					<span class="justification-content-label">Justification :</span>
					<p class="justification-content-text">{justificationHomework.ruleExceptionJustification ?? 'Non disponible'}</p>
				</div>
			</div>

			<div class="modal-actions">
				<button type="button" class="btn-secondary" onclick={() => { showJustificationModal = false; justificationHomework = null; }}>
					Fermer
				</button>
			</div>
		</div>
	</div>
{/if}

<style>
	.homework-page {
		padding: 1.5rem;
		max-width: 1200px;
		margin: 0 auto;
	}

	.page-header {
		display: flex;
		justify-content: space-between;
		align-items: flex-start;
		gap: 1rem;
		margin-bottom: 1.5rem;
		flex-wrap: wrap;
	}

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

	.subtitle {
		margin: 0.25rem 0 0;
		color: #6b7280;
		font-size: 0.875rem;
	}

	/* Buttons */
	.btn-primary {
		display: inline-flex;
		align-items: center;
		gap: 0.5rem;
		padding: 0.75rem 1.25rem;
		background: var(--btn-primary-bg, #3b82f6);
		color: white;
		border: none;
		border-radius: 0.5rem;
		font-weight: 600;
		cursor: pointer;
		transition: background 0.2s;
	}

	.btn-primary:hover:not(:disabled) {
		background: var(--btn-primary-hover-bg, #2563eb);
	}

	.btn-primary:disabled {
		opacity: 0.6;
		cursor: not-allowed;
	}

	.btn-secondary {
		padding: 0.5rem 1rem;
		background: white;
		color: #374151;
		border: 1px solid #d1d5db;
		border-radius: 0.375rem;
		font-weight: 500;
		cursor: pointer;
		transition: all 0.2s;
	}

	.btn-secondary:hover:not(:disabled) {
		background: #f3f4f6;
	}

	.btn-danger {
		padding: 0.5rem 1rem;
		background: #fef2f2;
		color: #dc2626;
		border: 1px solid #fecaca;
		border-radius: 0.375rem;
		font-weight: 500;
		cursor: pointer;
		transition: all 0.2s;
	}

	.btn-danger:hover:not(:disabled) {
		background: #fee2e2;
	}

	.btn-sm {
		padding: 0.375rem 0.75rem;
		font-size: 0.875rem;
	}

	.btn-icon {
		font-size: 1.25rem;
		line-height: 1;
	}

	/* Alert */
	.alert {
		display: flex;
		align-items: center;
		gap: 0.75rem;
		padding: 1rem;
		border-radius: 0.5rem;
		margin-bottom: 1rem;
	}

	.alert-error {
		background: #fef2f2;
		border: 1px solid #fecaca;
		color: #dc2626;
	}

	.alert-icon {
		flex-shrink: 0;
	}

	.alert-close {
		margin-left: auto;
		padding: 0.25rem 0.5rem;
		background: none;
		border: none;
		font-size: 1.25rem;
		cursor: pointer;
		opacity: 0.6;
	}

	.alert-close:hover {
		opacity: 1;
	}

	.alert-warning {
		background: #fffbeb;
		border: 1px solid #fde68a;
		color: #92400e;
	}

	.warning-list {
		margin: 0.25rem 0 0;
		padding-left: 1.25rem;
		font-size: 0.875rem;
	}

	/* Loading & Empty states */
	.loading-state,
	.empty-state {
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		padding: 3rem;
		text-align: center;
		background: white;
		border-radius: 0.75rem;
		border: 2px dashed #e5e7eb;
	}

	.spinner {
		width: 2rem;
		height: 2rem;
		border: 3px solid #e5e7eb;
		border-top-color: #3b82f6;
		border-radius: 50%;
		animation: spin 0.8s linear infinite;
	}

	@keyframes spin {
		to {
			transform: rotate(360deg);
		}
	}

	.empty-icon {
		font-size: 3rem;
		margin-bottom: 1rem;
	}

	.empty-state h2 {
		margin: 0 0 0.5rem;
		font-size: 1.25rem;
		color: #1f2937;
	}

	.empty-state p {
		margin: 0 0 1.5rem;
		color: #6b7280;
	}

	/* Homework list */
	.homework-list {
		display: flex;
		flex-direction: column;
		gap: 1rem;
	}

	.homework-card {
		padding: 1.25rem;
		background: white;
		border: 1px solid #e5e7eb;
		border-radius: 0.75rem;
		transition: box-shadow 0.2s;
	}

	.homework-card:hover {
		box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
	}

	.homework-card.overdue {
		border-left: 4px solid #dc2626;
	}

	.homework-header {
		display: flex;
		justify-content: space-between;
		align-items: flex-start;
		gap: 0.75rem;
		margin-bottom: 0.75rem;
	}

	.homework-title {
		margin: 0;
		font-size: 1.125rem;
		font-weight: 600;
		color: #1f2937;
	}

	.homework-status {
		flex-shrink: 0;
		padding: 0.125rem 0.5rem;
		border-radius: 9999px;
		font-size: 0.75rem;
		font-weight: 600;
	}

	.status-published {
		background: #dcfce7;
		color: #16a34a;
	}

	.status-deleted {
		background: #f3f4f6;
		color: #6b7280;
	}

	.homework-meta {
		display: flex;
		gap: 1.25rem;
		flex-wrap: wrap;
		margin-bottom: 0.75rem;
	}

	.meta-item {
		display: flex;
		align-items: center;
		gap: 0.25rem;
		font-size: 0.875rem;
		color: #6b7280;
	}

	.meta-icon {
		font-size: 0.875rem;
	}

	.overdue-date {
		color: #dc2626;
		font-weight: 600;
	}

	.homework-description {
		margin: 0 0 0.75rem;
		font-size: 0.875rem;
		color: #4b5563;
		line-height: 1.5;
	}

	.homework-description :global(ul) {
		list-style-type: disc;
		padding-left: 1.5rem;
	}

	.homework-description :global(ol) {
		list-style-type: decimal;
		padding-left: 1.5rem;
	}

	.homework-actions {
		display: flex;
		gap: 0.5rem;
	}

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

	.modal {
		background: white;
		border-radius: 0.75rem;
		width: 100%;
		max-width: 32rem;
		max-height: 90vh;
		overflow: auto;
		box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
	}

	.modal-header {
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 1.25rem 1.5rem;
		border-bottom: 1px solid #e5e7eb;
	}

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

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

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

	.modal-body {
		padding: 1.5rem;
	}

	.form-group {
		margin-bottom: 1.25rem;
	}

	.form-group label,
	.field-label {
		display: block;
		margin-bottom: 0.5rem;
		font-weight: 500;
		color: #374151;
	}

	.form-group input[type='text'],
	.form-group input[type='date'],
	.form-group select {
		width: 100%;
		padding: 0.75rem 1rem;
		border: 1px solid #d1d5db;
		border-radius: 0.375rem;
		font-size: 1rem;
		transition: border-color 0.2s;
	}

	.form-group textarea {
		width: 100%;
		padding: 0.75rem 1rem;
		border: 1px solid #d1d5db;
		border-radius: 0.375rem;
		font-size: 1rem;
		resize: vertical;
		min-height: 80px;
		transition: border-color 0.2s;
	}

	.form-group input:focus,
	.form-group select:focus,
	.form-group textarea:focus {
		outline: none;
		border-color: #3b82f6;
		box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
	}

	.form-group select:disabled {
		background: #f9fafb;
		color: #9ca3af;
		cursor: not-allowed;
	}

	.form-hint {
		display: block;
		margin-top: 0.25rem;
		font-size: 0.75rem;
		color: #6b7280;
	}

	.form-hint-warning {
		color: #d97706;
	}

	.form-info {
		display: grid;
		grid-template-columns: auto 1fr;
		gap: 0.25rem 0.75rem;
		padding: 0.75rem 1rem;
		margin-bottom: 1.25rem;
		background: #f9fafb;
		border-radius: 0.375rem;
		font-size: 0.875rem;
	}

	.info-label {
		font-weight: 600;
		color: #374151;
	}

	.modal-actions {
		display: flex;
		justify-content: flex-end;
		gap: 0.75rem;
		padding-top: 1rem;
		border-top: 1px solid #e5e7eb;
	}

	/* Delete confirmation modal */
	.modal-confirm {
		max-width: 24rem;
	}

	.modal-confirm .modal-actions {
		padding: 1rem 1.5rem;
		border-top: 1px solid #e5e7eb;
	}

	.modal-header-danger {
		background: #fef2f2;
		border-bottom-color: #fecaca;
	}

	.modal-header-danger h2 {
		color: #dc2626;
	}

	.delete-warning {
		margin: 0.75rem 0 0;
		font-size: 0.875rem;
		color: #6b7280;
	}

	/* Filters row */
	.filters-row {
		display: flex;
		gap: 1rem;
		align-items: flex-start;
		margin-bottom: 1rem;
		flex-wrap: wrap;
	}

	.filters-row > :first-child {
		flex: 1;
		min-width: 200px;
	}

	.class-filter select {
		padding: 0.625rem 1rem;
		border: 1px solid #d1d5db;
		border-radius: 0.375rem;
		font-size: 0.875rem;
		background: white;
		cursor: pointer;
	}

	.class-filter select:focus {
		outline: none;
		border-color: #3b82f6;
		box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
	}

	/* Duplicate modal */
	.checkbox-list {
		display: flex;
		flex-direction: column;
		gap: 0.75rem;
	}

	.checkbox-item {
		padding: 0.75rem;
		border: 1px solid #e5e7eb;
		border-radius: 0.375rem;
	}

	.checkbox-item.validation-error {
		border-color: #fecaca;
		background: #fef2f2;
	}

	.checkbox-label {
		display: flex;
		align-items: center;
		gap: 0.5rem;
		cursor: pointer;
		font-weight: 500;
	}

	.checkbox-label input[type='checkbox'] {
		width: 1rem;
		height: 1rem;
	}

	.due-date-inline {
		display: flex;
		align-items: center;
		gap: 0.5rem;
		margin-top: 0.5rem;
		padding-left: 1.5rem;
	}

	.due-date-inline label {
		font-size: 0.875rem;
		color: #6b7280;
		white-space: nowrap;
	}

	.due-date-inline input[type='date'] {
		padding: 0.375rem 0.5rem;
		border: 1px solid #d1d5db;
		border-radius: 0.375rem;
		font-size: 0.875rem;
	}

	.empty-target-classes {
		text-align: center;
		color: #6b7280;
		padding: 2rem 0;
	}

	/* Rule conforming date hint */
	.form-hint-rule {
		color: #d97706;
		font-weight: 500;
	}

	.form-hint-error {
		color: #dc2626;
		font-weight: 500;
	}

	/* Rule override badge */
	.homework-badges {
		display: flex;
		align-items: center;
		gap: 0.5rem;
	}

	.badge-rule-override {
		font-size: 0.75rem;
		color: #d97706;
		opacity: 0.7;
		cursor: help;
	}

	.badge-rule-exception {
		font-size: 0.7rem;
		color: #92400e;
		background: #fffbeb;
		border: 1px solid #fde68a;
		border-radius: 9999px;
		padding: 0.125rem 0.5rem;
		font-weight: 600;
		cursor: pointer;
		transition: all 0.2s;
	}

	.badge-rule-exception:hover {
		background: #fef3c7;
		border-color: #f59e0b;
	}

	/* Justification viewing modal */
	.modal-header-exception-view {
		background: #f59e0b;
		color: white;
		border-radius: 0.75rem 0.75rem 0 0;
	}

	.modal-header-exception-view h2 {
		margin: 0;
		font-size: 1.1rem;
	}

	.justification-info {
		display: grid;
		grid-template-columns: auto 1fr;
		gap: 0.25rem 0.75rem;
		padding: 0.75rem 1rem;
		margin-bottom: 1rem;
		background: #f9fafb;
		border-radius: 0.375rem;
		font-size: 0.875rem;
	}

	.justification-info-label {
		font-weight: 600;
		color: #374151;
	}

	.justification-content {
		padding: 0.75rem 1rem;
		background: #fffbeb;
		border: 1px solid #fde68a;
		border-radius: 0.375rem;
	}

	.justification-content-label {
		font-size: 0.75rem;
		font-weight: 600;
		color: #92400e;
		text-transform: uppercase;
	}

	.justification-content-text {
		margin: 0.25rem 0 0;
		font-size: 0.875rem;
		color: #374151;
		line-height: 1.5;
		font-style: italic;
	}

	/* Rule Warning Modal */
	.modal-header-warning {
		border-bottom: 3px solid #f59e0b;
	}

	.modal-header-warning h2 {
		color: #d97706;
	}

	.rule-warning-list {
		list-style: none;
		padding: 0;
		margin: 1rem 0;
	}

	.rule-warning-item {
		display: flex;
		align-items: flex-start;
		gap: 0.5rem;
		padding: 0.75rem;
		background: #fffbeb;
		border: 1px solid #fde68a;
		border-radius: 0.375rem;
		margin-bottom: 0.5rem;
		color: #92400e;
	}

	.rule-warning-icon {
		color: #d97706;
		flex-shrink: 0;
	}

	.rule-warning-notice {
		font-size: 0.875rem;
		color: #6b7280;
		font-style: italic;
		margin-top: 1rem;
	}
</style>
