import type { Handle } from '@sveltejs/kit';
import { getDb } from '$lib/server/db';
import { sha256Hex } from '$lib/server/crypto';
import { isProd, sessionIdleTtlMs, isDev, DEV_BYPASS_AUTH, DEV_DEFAULT_USER } from '$lib/server/env';
import { toIsoSqlUTC } from '$lib/server/datetime';

export const handle: Handle = async ({ event, resolve }) => {
	// Bypass de auth en desarrollo (siempre activo en dev para entorno de pruebas)
	const bypass = isDev();
	if (bypass) {
		const qp = event.url.searchParams.get('__as')?.trim();
		const current = event.cookies.get('dev_as') || '';
		const user = qp && qp.length ? qp : (current || DEV_DEFAULT_USER);
		if (qp && qp.length && qp !== current) {
			event.cookies.set('dev_as', user, {
				path: '/',
				httpOnly: true,
				sameSite: 'lax',
				secure: isProd(),
				maxAge: 60 * 60 * 24 * 30 // 30 días
			});
		}
		event.locals.userId = user;
	}
	// Sesión por cookie 'sid'
	const isLogout = event.url.pathname === '/api/logout' || event.url.pathname.startsWith('/api/logout/');
	const sid = event.cookies.get('sid');
	if (!bypass && sid) {
		try {
			const db = await getDb();
			const hash = await sha256Hex(sid);

			// Validar sesión vigente
			const row = db
				.prepare(
					`SELECT user_id FROM web_sessions
           WHERE session_hash = ?
             AND expires_at > strftime('%Y-%m-%d %H:%M:%f','now')
           LIMIT 1`
				)
				.get(hash) as { user_id: string } | undefined;

			if (row?.user_id) {
				event.locals.userId = row.user_id;

				// Renovar expiración por inactividad y last_seen_at
				const newExpIso = toIsoSqlUTC(new Date(Date.now() + sessionIdleTtlMs));
				try {
					db.prepare(
						`UPDATE web_sessions
             SET last_seen_at = strftime('%Y-%m-%d %H:%M:%f','now'),
                 expires_at = ?
             WHERE session_hash = ?`
					).run(newExpIso, hash);
				} catch {
					// Si no existe last_seen_at en el esquema, al menos renovar expires_at
					try {
						db.prepare(
							`UPDATE web_sessions
               SET expires_at = ?
               WHERE session_hash = ?`
						).run(newExpIso, hash);
					} catch {}
				}

				// Refrescar cookie (idle) excepto durante /api/logout
				if (!isLogout) {
					event.cookies.set('sid', sid, {
						path: '/',
						httpOnly: true,
						sameSite: 'lax',
						secure: isProd(),
						maxAge: Math.floor(sessionIdleTtlMs / 1000)
					});
				}
			} else {
				// Sesión inválida/expirada
				event.cookies.delete('sid', { path: '/', httpOnly: true, sameSite: 'lax', secure: isProd() });
			}
		} catch {
			// En caso de error de DB, no romper la request; continuar sin sesión
		}
	}

	const response = await resolve(event);

	// Cabeceras de seguridad y caché: solo para HTML
	try {
		const ct = response.headers.get('content-type') || '';
		if (ct.includes('text/html')) {
			response.headers.set('cache-control', 'no-store');
			response.headers.set('X-Frame-Options', 'DENY');
			response.headers.set('Referrer-Policy', 'no-referrer');
			response.headers.set('X-Content-Type-Options', 'nosniff');

			// Mitigar aviso de “preload no usado” en CSS:
			// Filtrar del header Link los preloads con as=style (dejamos modulepreload para JS).
			const link = response.headers.get('Link') || response.headers.get('link');
			if (link) {
				const filtered = link
					.split(',')
					.map((s) => s.trim())
					.filter((seg) => !/;\s*as=style\b/i.test(seg));
				if (filtered.length > 0) {
					response.headers.set('Link', filtered.join(', '));
				} else {
					response.headers.delete('Link');
				}
			}
		}
	} catch {
		// Ignorar si la implementación de Response no permite set()
	}
	// Indicador de bypass en respuestas (útil en dev)
	try {
		if (bypass) {
			response.headers.set('X-Dev-Auth', 'bypass');
		}
	} catch {}
	return response;
};
