import { browser } from '$app/environment';
import type { PpClientConfig, PpSessionResponse, PpUser } from '$lib/types/photoprism';

const STORAGE_KEY = 'pp_session';

interface PersistedSession {
	id: string;
	accessToken: string;
	previewToken: string;
	downloadToken: string;
	user: PpUser;
}

function loadInitial(): PersistedSession | null {
	if (!browser) return null;
	try {
		const raw = localStorage.getItem(STORAGE_KEY);
		if (!raw) return null;
		return JSON.parse(raw) as PersistedSession;
	} catch {
		return null;
	}
}

/**
 * Single-source session state for the Svelte client. Components import the
 * `session` object and read its reactive fields; mutations go through the
 * helpers below. State is mirrored to localStorage so a hard refresh keeps
 * the user signed in.
 */
const initial = loadInitial();

export const session = $state<{
	id: string | null;
	accessToken: string | null;
	previewToken: string | null;
	downloadToken: string | null;
	user: PpUser | null;
}>({
	id: initial?.id ?? null,
	accessToken: initial?.accessToken ?? null,
	previewToken: initial?.previewToken ?? null,
	downloadToken: initial?.downloadToken ?? null,
	user: initial?.user ?? null
});

export function isAuthenticated(): boolean {
	return Boolean(session.accessToken);
}

export function adoptSession(resp: PpSessionResponse, cfg?: PpClientConfig): void {
	session.id = resp.id;
	session.accessToken = resp.access_token;
	session.previewToken = (cfg ?? resp.config)?.previewToken ?? '';
	session.downloadToken = (cfg ?? resp.config)?.downloadToken ?? '';
	session.user = resp.user;
	persist();
}

export function clearSession(): void {
	session.id = null;
	session.accessToken = null;
	session.previewToken = null;
	session.downloadToken = null;
	session.user = null;
	if (browser) localStorage.removeItem(STORAGE_KEY);
}

function persist(): void {
	if (!browser || !session.accessToken) return;
	const payload: PersistedSession = {
		id: session.id ?? '',
		accessToken: session.accessToken,
		previewToken: session.previewToken ?? '',
		downloadToken: session.downloadToken ?? '',
		user: session.user!
	};
	localStorage.setItem(STORAGE_KEY, JSON.stringify(payload));
}

/**
 * Build a thumbnail URL for a photo. PhotoPrism's thumb endpoint is
 * /api/v1/t/:hash/:token/:size — the token is the per-session
 * previewToken, which the session response provides on login.
 */
export function thumbUrl(hash: string, size = 'tile_500'): string {
	if (!session.previewToken) return '';
	return `/api/v1/t/${hash}/${session.previewToken}/${size}`;
}

/**
 * PhotoPrism's square-cropped tile sizes (px). These are the variants
 * the indexer generates by default for the `tile_*` family. fit_* exists
 * for non-square sizing but is the wrong fit for grid cells with
 * `object-cover` — we always render a square.
 */
const TILE_SIZES = [100, 224, 500] as const;

/**
 * Pick the smallest PhotoPrism tile variant whose pixel count is at or
 * above the on-screen target. Falls through to the largest (500) for
 * anything bigger — we don't have a tile_720+ variant. Used by both the
 * 1x and 2x slots of the srcset helper below.
 */
function pickTileSize(targetPx: number): string {
	for (const s of TILE_SIZES) {
		if (s >= targetPx) return `tile_${s}`;
	}
	return `tile_${TILE_SIZES[TILE_SIZES.length - 1]}`;
}

/**
 * Build a thumbnail `srcset` for a photo at a given on-screen tile
 * size. The browser picks the right variant for the current device
 * pixel ratio — on a 2x display we serve `tile_500` for a 272px XL
 * tile, on a 1x display the same tile gets `tile_500` only if no
 * smaller variant covers it, so most users save bandwidth.
 *
 * Returns the `srcset` value (no `src` attribute — pair with `thumbUrl`
 * for the 1x fallback). Two variants is enough: PhotoPrism only
 * indexes three square sizes (100/224/500), so 1x and 2x cover the
 * realistic DPR range without flooding the cache.
 */
export function thumbSrcSet(hash: string, targetPx: number): string {
	if (!session.previewToken) return '';
	const one = pickTileSize(targetPx);
	const two = pickTileSize(targetPx * 2);
	const url1x = thumbUrl(hash, one);
	const url2x = thumbUrl(hash, two);
	if (url1x === url2x) return `${url1x} 1x`;
	return `${url1x} 1x, ${url2x} 2x`;
}

/** Companion to `thumbSrcSet` — the `src` attribute value (1x). */
export function thumbSrc(hash: string, targetPx: number): string {
	if (!session.previewToken) return '';
	return thumbUrl(hash, pickTileSize(targetPx));
}

/**
 * Build a video stream URL. PhotoPrism's endpoint is
 * /api/v1/videos/:hash/:token/:format — same previewToken as thumbnails.
 * `format=avc` is the standard h264 transcode; HEVC sources are
 * transcoded on first request and cached server-side.
 */
export function videoUrl(hash: string, format = 'avc'): string {
	if (!session.previewToken) return '';
	return `/api/v1/videos/${hash}/${session.previewToken}/${format}`;
}
