<script lang="ts">
	import { getApiBaseUrl } from '$lib/api/config';
	import { authenticatedFetch } from '$lib/auth/auth.svelte';
	import {
		updateBranding,
		getBranding,
		type BrandingConfig
	} from '$features/branding/brandingStore.svelte';

	// State
	let branding = $state<BrandingConfig | null>(null);
	let isLoading = $state(true);
	let error = $state<string | null>(null);
	let successMessage = $state<string | null>(null);

	// Color form state
	let primaryColor = $state<string | null>(null);
	let isSavingColors = $state(false);

	// Logo state
	let isUploadingLogo = $state(false);
	let isDeletingLogo = $state(false);
	let fileInput = $state<HTMLInputElement>();

	// Contrast computation
	const HEX_PATTERN = /^#[0-9A-Fa-f]{6}$/;
	let isValidHex = $derived(primaryColor ? HEX_PATTERN.test(primaryColor) : false);

	let contrastInfo = $derived.by(() => {
		if (!primaryColor || !isValidHex) return null;
		return computeContrast(primaryColor, '#FFFFFF');
	});

	// Track unsaved color changes — block save if contrast fails WCAG AA
	let contrastBlocked = $derived(contrastInfo !== null && !contrastInfo.passesAA);
	let hasColorChanges = $derived(
		primaryColor !== (branding?.primaryColor ?? null) &&
			(primaryColor === null || isValidHex) &&
			!contrastBlocked
	);

	// Load branding on mount
	$effect(() => {
		loadBranding();
	});

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

			// Try store first
			const cached = getBranding();
			if (cached) {
				branding = cached;
				syncFormFromBranding(cached);
				isLoading = false;
				return;
			}

			const apiUrl = getApiBaseUrl();
			const response = await authenticatedFetch(`${apiUrl}/school/branding`);

			if (!response.ok) {
				throw new Error('Impossible de charger la configuration du branding.');
			}

			const data: BrandingConfig = await response.json();
			branding = data;
			syncFormFromBranding(data);
		} catch (e) {
			error = e instanceof Error ? e.message : 'Erreur inconnue';
		} finally {
			isLoading = false;
		}
	}

	function syncFormFromBranding(config: BrandingConfig) {
		primaryColor = config.primaryColor;
	}

	async function handleSaveColors() {
		try {
			isSavingColors = true;
			error = null;
			successMessage = null;

			const apiUrl = getApiBaseUrl();
			const response = await authenticatedFetch(`${apiUrl}/school/branding`, {
				method: 'PUT',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({
					primaryColor,
					secondaryColor: null,
					accentColor: null
				})
			});

			if (!response.ok) {
				const errorData = await response.json();
				throw new Error(
					errorData['hydra:description'] || errorData.message || 'Erreur lors de la sauvegarde.'
				);
			}

			const data: BrandingConfig = await response.json();
			branding = data;
			syncFormFromBranding(data);
			updateBranding(data);
			successMessage = 'Couleurs mises à jour avec succès.';
			setTimeout(() => (successMessage = null), 4000);
		} catch (e) {
			error = e instanceof Error ? e.message : 'Erreur';
		} finally {
			isSavingColors = false;
		}
	}

	async function handleUploadLogo() {
		const file = fileInput?.files?.[0];
		if (!file) return;

		try {
			isUploadingLogo = true;
			error = null;
			successMessage = null;

			const formData = new window.FormData();
			formData.append('file', file);

			const apiUrl = getApiBaseUrl();
			const response = await authenticatedFetch(`${apiUrl}/school/branding/logo`, {
				method: 'POST',
				body: formData
			});

			if (!response.ok) {
				const errorData = await response.json();
				throw new Error(
					errorData['hydra:description'] || errorData.message || 'Erreur lors de l\'upload.'
				);
			}

			const data: BrandingConfig = await response.json();
			branding = data;
			syncFormFromBranding(data);
			updateBranding(data);
			successMessage = 'Logo mis à jour avec succès.';
			setTimeout(() => (successMessage = null), 4000);

			// Reset file input
			if (fileInput) fileInput.value = '';
		} catch (e) {
			error = e instanceof Error ? e.message : 'Erreur';
		} finally {
			isUploadingLogo = false;
		}
	}

	async function handleDeleteLogo(skipConfirm = false) {
		if (!skipConfirm && !window.confirm('Êtes-vous sûr de vouloir supprimer le logo ?')) return;

		try {
			isDeletingLogo = true;
			error = null;
			successMessage = null;

			const apiUrl = getApiBaseUrl();
			const response = await authenticatedFetch(`${apiUrl}/school/branding/logo`, {
				method: 'DELETE'
			});

			if (!response.ok && response.status !== 204) {
				throw new Error('Erreur lors de la suppression du logo.');
			}

			if (branding) {
				branding = { ...branding, logoUrl: null, logoUpdatedAt: null };
				updateBranding(branding);
			}
			if (!skipConfirm) {
				successMessage = 'Logo supprimé avec succès.';
				setTimeout(() => (successMessage = null), 4000);
			}
		} catch (e) {
			error = e instanceof Error ? e.message : 'Erreur';
		} finally {
			isDeletingLogo = false;
		}
	}

	async function handleReset() {
		if (!window.confirm('Réinitialiser toutes les personnalisations vers le thème par défaut ?')) return;

		if (branding?.logoUrl) {
			await handleDeleteLogo(true);
		}
		primaryColor = null;
		await handleSaveColors();
	}

	// WCAG contrast computation
	function computeContrast(
		fg: string,
		bg: string
	): { ratio: number; passesAA: boolean; passesAALarge: boolean } {
		const fgRgb = hexToRgb(fg);
		const bgRgb = hexToRgb(bg);
		if (!fgRgb || !bgRgb) return { ratio: 0, passesAA: false, passesAALarge: false };

		const l1 = relativeLuminance(fgRgb);
		const l2 = relativeLuminance(bgRgb);
		const lighter = Math.max(l1, l2);
		const darker = Math.min(l1, l2);
		const ratio = (lighter + 0.05) / (darker + 0.05);

		return {
			ratio: Math.round(ratio * 100) / 100,
			passesAA: ratio >= 4.5,
			passesAALarge: ratio >= 3.0
		};
	}

	function hexToRgb(hex: string): { r: number; g: number; b: number } | null {
		const match = hex.match(/^#([0-9A-Fa-f]{6})$/);
		if (!match?.[1]) return null;
		const hex6 = match[1];
		return {
			r: parseInt(hex6.substring(0, 2), 16),
			g: parseInt(hex6.substring(2, 4), 16),
			b: parseInt(hex6.substring(4, 6), 16)
		};
	}

	function relativeLuminance(rgb: { r: number; g: number; b: number }): number {
		const r = linearize(rgb.r / 255);
		const g = linearize(rgb.g / 255);
		const b = linearize(rgb.b / 255);
		return 0.2126 * r + 0.7152 * g + 0.0722 * b;
	}

	function linearize(v: number): number {
		return v <= 0.03928 ? v / 12.92 : Math.pow((v + 0.055) / 1.055, 2.4);
	}
</script>

<svelte:head>
	<title>Identité visuelle - Classeo</title>
</svelte:head>

<header class="page-header">
	<div class="header-content">
		<h1>Identité visuelle</h1>
		<p class="subtitle">Personnalisez le logo et les couleurs de votre établissement.</p>
	</div>
</header>

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

{#if successMessage}
	<div class="alert alert-success" role="status">
		<span>{successMessage}</span>
		<button class="alert-close" onclick={() => (successMessage = null)}>&times;</button>
	</div>
{/if}

{#if isLoading}
	<div class="loading-state">
		<div class="spinner"></div>
		<p>Chargement...</p>
	</div>
{:else}
	<!-- Logo Section -->
	<section class="card">
		<h2>Logo de l'établissement</h2>
		<p class="section-description">
			Formats acceptés : PNG, JPG. Taille maximale : 2 Mo. Le logo sera redimensionné automatiquement.
		</p>

		<div class="logo-section">
			{#if branding?.logoUrl}
				<div class="logo-preview">
					<img src={branding.logoUrl} alt="Logo de l'établissement" class="logo-image" />
				</div>
				<div class="logo-actions">
					<label class="btn-secondary btn-file">
						Changer le logo
						<input
							type="file"
							accept="image/png,image/jpeg"
							bind:this={fileInput}
							onchange={handleUploadLogo}
							hidden
						/>
					</label>
					<button
						class="btn-danger"
						onclick={() => handleDeleteLogo()}
						disabled={isDeletingLogo}
					>
						{isDeletingLogo ? 'Suppression...' : 'Supprimer'}
					</button>
				</div>
			{:else}
				<div class="logo-placeholder">
					<span class="logo-placeholder-icon">+</span>
					<p>Aucun logo configuré</p>
				</div>
				<label class="btn-primary btn-file">
					{#if isUploadingLogo}
						Upload en cours...
					{:else}
						Importer un logo
					{/if}
					<input
						type="file"
						accept="image/png,image/jpeg"
						bind:this={fileInput}
						onchange={handleUploadLogo}
						disabled={isUploadingLogo}
						hidden
					/>
				</label>
			{/if}
		</div>
	</section>

	<!-- Colors Section -->
	<section class="card">
		<h2>Couleur principale</h2>
		<p class="section-description">
			Définissez la couleur de votre établissement. Elle sera appliquée aux boutons, à la navigation
			et aux éléments actifs. Laissez vide pour utiliser le thème par défaut Classeo.
		</p>

		<div class="color-field">
			<label for="primaryColor">Couleur</label>
			<div class="color-input-group">
				<input
					type="color"
					id="primaryColorPicker"
					value={primaryColor ?? '#3B82F6'}
					onchange={(e) => (primaryColor = e.currentTarget.value.toUpperCase())}
				/>
				<input
					type="text"
					id="primaryColor"
					placeholder="#3B82F6"
					value={primaryColor ?? ''}
					oninput={(e) => {
						const val = e.currentTarget.value;
						primaryColor = val ? val.toUpperCase() : null;
					}}
					pattern="^#[0-9A-Fa-f]{6}$"
				/>
				{#if primaryColor}
					<button
						class="color-clear"
						onclick={() => (primaryColor = null)}
						title="Effacer"
					>
						&times;
					</button>
				{/if}
			</div>
			{#if contrastInfo}
				<div
					class="contrast-indicator"
					class:pass={contrastInfo.passesAA}
					class:warning={!contrastInfo.passesAA && contrastInfo.passesAALarge}
					class:fail={!contrastInfo.passesAALarge}
				>
					{#if contrastInfo.passesAA}
						<span class="contrast-badge">Lisible</span>
						<span>Le texte blanc sur cette couleur est facile à lire.</span>
					{:else if contrastInfo.passesAALarge}
						<span class="contrast-badge">Attention</span>
						<span>Le texte blanc est lisible en gros uniquement. Les petits textes seront difficiles à lire.</span>
					{:else}
						<span class="contrast-badge">Illisible</span>
						<span>Cette couleur est trop claire : le texte blanc sur les boutons sera difficile à lire. Choisissez une couleur plus foncée.</span>
					{/if}
				</div>
			{/if}
		</div>

		{#if primaryColor}
			<div class="preview-section">
				<h3>Aperçu</h3>
				<div class="preview-bar">
					<div class="preview-swatch" style="background-color: {primaryColor}">
						<span style="color: white">Boutons</span>
					</div>
					<div class="preview-swatch preview-swatch-nav" style="border-color: {primaryColor}; color: {primaryColor}">
						Navigation active
					</div>
				</div>
			</div>
		{/if}

		<div class="form-actions">
			<button class="btn-secondary" onclick={handleReset} disabled={isSavingColors}>
				Réinitialiser
			</button>
			<button
				class="btn-primary"
				onclick={handleSaveColors}
				disabled={isSavingColors || !hasColorChanges}
			>
				{isSavingColors ? 'Enregistrement...' : 'Enregistrer'}
			</button>
		</div>
	</section>
{/if}

<style>
	.page-header {
		margin-bottom: 1.5rem;
	}

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

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

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

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

	.section-description {
		color: #6b7280;
		font-size: 0.875rem;
		margin: 0 0 1.25rem;
	}

	/* Alerts */
	.alert {
		display: flex;
		justify-content: space-between;
		align-items: center;
		padding: 0.75rem 1rem;
		border-radius: 0.5rem;
		margin-bottom: 1rem;
		font-size: 0.875rem;
	}

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

	.alert-success {
		background: #f0fdf4;
		border: 1px solid #bbf7d0;
		color: #166534;
	}

	.alert-close {
		background: none;
		border: none;
		font-size: 1.25rem;
		cursor: pointer;
		color: inherit;
		padding: 0 0.25rem;
	}

	/* Loading */
	.loading-state {
		text-align: center;
		padding: 3rem 1rem;
		color: #6b7280;
	}

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

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

	/* Logo section */
	.logo-section {
		display: flex;
		align-items: center;
		gap: 1.5rem;
		flex-wrap: wrap;
	}

	.logo-preview {
		width: 120px;
		height: 120px;
		border: 2px solid #e5e7eb;
		border-radius: 0.75rem;
		overflow: hidden;
		display: flex;
		align-items: center;
		justify-content: center;
		background: #f9fafb;
	}

	.logo-image {
		max-width: 100%;
		max-height: 100%;
		object-fit: contain;
	}

	.logo-placeholder {
		width: 120px;
		height: 120px;
		border: 2px dashed #d1d5db;
		border-radius: 0.75rem;
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: center;
		color: #9ca3af;
		gap: 0.25rem;
	}

	.logo-placeholder-icon {
		font-size: 1.5rem;
		font-weight: 300;
	}

	.logo-placeholder p {
		font-size: 0.75rem;
		margin: 0;
		text-align: center;
	}

	.logo-actions {
		display: flex;
		flex-direction: column;
		gap: 0.5rem;
	}

	/* Colors */
	.color-field {
		margin-bottom: 1.5rem;
	}

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

	.color-input-group {
		display: flex;
		align-items: center;
		gap: 0.5rem;
	}

	.color-input-group input[type='color'] {
		width: 2.5rem;
		height: 2.5rem;
		padding: 2px;
		border: 1px solid #d1d5db;
		border-radius: 0.375rem;
		cursor: pointer;
		flex-shrink: 0;
	}

	.color-input-group input[type='text'] {
		flex: 1;
		padding: 0.625rem 0.75rem;
		border: 1px solid #d1d5db;
		border-radius: 0.375rem;
		font-size: 0.875rem;
		font-family: monospace;
	}

	.color-input-group input[type='text']:focus {
		outline: none;
		border-color: #3b82f6;
		box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
	}

	.color-clear {
		background: none;
		border: none;
		font-size: 1.25rem;
		color: #9ca3af;
		cursor: pointer;
		padding: 0.25rem;
		line-height: 1;
	}

	.color-clear:hover {
		color: #ef4444;
	}

	/* Contrast indicator */
	.contrast-indicator {
		display: flex;
		align-items: center;
		gap: 0.5rem;
		margin-top: 0.5rem;
		font-size: 0.75rem;
		font-weight: 500;
	}

	.contrast-indicator.pass {
		color: #166534;
	}

	.contrast-indicator.warning {
		color: #92400e;
	}

	.contrast-indicator.fail {
		color: #991b1b;
	}

	.contrast-badge {
		display: inline-flex;
		align-items: center;
		padding: 0.125rem 0.5rem;
		border-radius: 9999px;
		font-size: 0.6875rem;
		font-weight: 600;
	}

	.contrast-indicator.pass .contrast-badge {
		background: #dcfce7;
		color: #166534;
	}

	.contrast-indicator.warning .contrast-badge {
		background: #fef3c7;
		color: #92400e;
	}

	.contrast-indicator.fail .contrast-badge {
		background: #fef2f2;
		color: #991b1b;
	}

	/* Preview */
	.preview-section {
		margin-bottom: 1.5rem;
	}

	.preview-section h3 {
		font-size: 0.875rem;
		font-weight: 600;
		color: #374151;
		margin: 0 0 0.75rem;
	}

	.preview-bar {
		display: flex;
		gap: 0.75rem;
		flex-wrap: wrap;
	}

	.preview-swatch {
		display: flex;
		align-items: center;
		justify-content: center;
		width: 120px;
		height: 60px;
		border-radius: 0.5rem;
		font-size: 0.75rem;
		font-weight: 500;
		box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
	}

	.preview-swatch-nav {
		background: #f8fafc;
		border: 2px solid;
		box-shadow: none;
	}

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

	.btn-primary {
		padding: 0.625rem 1.25rem;
		background: var(--btn-primary-bg, #3b82f6);
		color: white;
		border: none;
		border-radius: 0.5rem;
		font-weight: 600;
		font-size: 0.875rem;
		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.625rem 1.25rem;
		background: white;
		color: #374151;
		border: 1px solid #d1d5db;
		border-radius: 0.5rem;
		font-weight: 500;
		font-size: 0.875rem;
		cursor: pointer;
		transition: all 0.2s;
	}

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

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

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

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

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

	.btn-file {
		display: inline-flex;
		align-items: center;
		cursor: pointer;
	}
</style>
