import { readFileSync, existsSync } from 'fs';
import { resolve } from 'path';
import { json, error } from '@sveltejs/kit';
import {
	readCachedEmbyUserContext,
	writeCachedEmbyUserContext
} from '../../../lib/server/emby-user-context-cache.js';

const CONFIG_PATH = resolve('config.json');
const EMBY_PAGE_SIZE = 200;

function loadConfig() {
	if (!existsSync(CONFIG_PATH)) return {};
	try {
		return JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));
	} catch {
		return {};
	}
}

function normalizeGuid(value) {
	return typeof value === 'string' ? value.replace(/-/g, '').trim().toLowerCase() : '';
}

async function fetchJson(url) {
	const response = await fetch(url);
	if (!response.ok) {
		throw new Error(`${response.status} ${response.statusText}`);
	}
	return response.json();
}

async function fetchAllUserItems(base, embyGuid, apiKey, params = {}) {
	const allItems = [];
	let startIndex = 0;

	while (true) {
		const query = new URLSearchParams({
			api_key: apiKey,
			Recursive: 'true',
			GroupItemsIntoCollections: 'false',
			Limit: String(EMBY_PAGE_SIZE),
			StartIndex: String(startIndex),
			...Object.fromEntries(
				Object.entries(params).map(([key, value]) => [key, String(value)])
			)
		});
		const payload = await fetchJson(`${base}/Users/${encodeURIComponent(embyGuid)}/Items?${query.toString()}`);
		const pageItems = payload.Items || payload || [];
		allItems.push(...pageItems);

		const total = Number(payload.TotalRecordCount || 0);
		if (!pageItems.length) break;
		if (total > 0 && allItems.length >= total) break;
		if (pageItems.length < EMBY_PAGE_SIZE) break;

		startIndex += pageItems.length;
	}

	return allItems;
}

function normalizeViews(items = []) {
	return items.map((item) => ({
		id: String(item.Id || ''),
		name: item.Name || 'Unnamed view',
		type: item.CollectionType || item.Type || 'View'
	}));
}

function normalizeRecentlyPlayed(items = []) {
	return items.map((item) => ({
		id: String(item.Id || ''),
		name: item.Name || item.SeriesName || 'Unknown item',
		type: item.Type || 'Item',
		seriesName: item.SeriesName || null,
		datePlayed: item.UserData?.LastPlayedDate || item.DateLastMediaAdded || null,
		isPlayed: item.UserData?.Played ?? true
	}));
}

function buildExcludedFolderLookup(items = []) {
	return Object.fromEntries(
		items
			.filter((item) => item?.Id)
			.map((item) => [
				String(item.Id),
				{
					name: item.Name || item.Path || `Item ${item.Id}`,
					type: item.CollectionType || item.Type || 'Item'
				}
			])
	);
}

export async function GET({ url }) {
	const embyGuid = normalizeGuid(url.searchParams.get('embyGuid'));
	const excludedIds = (url.searchParams.get('excludedIds') || '')
		.split(',')
		.map((id) => id.trim())
		.filter(Boolean);

	if (!embyGuid) {
		throw error(400, 'Missing embyGuid');
	}

	const { embyUrl, apiKey } = loadConfig();
	const cached = readCachedEmbyUserContext(embyGuid);

	if (!embyUrl || !apiKey) {
		if (cached) {
			return json({ ...cached, source: 'cache' });
		}
		throw error(400, 'Emby URL and API key not configured');
	}

	const base = embyUrl.replace(/\/+$/, '');

	try {
		const [viewsPayload, recentlyPlayedPayload, excludedPayload] = await Promise.all([
			fetchJson(`${base}/Users/${encodeURIComponent(embyGuid)}/Views?api_key=${encodeURIComponent(apiKey)}`),
			fetchAllUserItems(base, embyGuid, apiKey, {
				Filters: 'IsPlayed',
				IncludeItemTypes: 'Movie,Series',
				SortBy: 'DatePlayed',
				SortOrder: 'Descending',
				Fields: 'UserData'
			}),
			excludedIds.length > 0
				? fetchJson(
					`${base}/Users/${encodeURIComponent(embyGuid)}/Items?api_key=${encodeURIComponent(apiKey)}&Ids=${encodeURIComponent(excludedIds.join(','))}&Fields=Path`
				)
				: Promise.resolve({ Items: [] })
		]);

		const context = writeCachedEmbyUserContext(embyGuid, {
			views: normalizeViews(viewsPayload.Items || viewsPayload || []),
			recentlyPlayed: normalizeRecentlyPlayed(recentlyPlayedPayload),
			excludedFolderLookup: buildExcludedFolderLookup(excludedPayload.Items || excludedPayload || []),
			lastSyncedAt: new Date().toISOString()
		});

		return json({ ...context, source: 'live' });
	} catch (err) {
		if (cached) {
			const filteredLookup = excludedIds.length
				? Object.fromEntries(
					Object.entries(cached.excludedFolderLookup || {}).filter(([id]) => excludedIds.includes(id))
				)
				: (cached.excludedFolderLookup || {});
			return json({
				...cached,
				excludedFolderLookup: filteredLookup,
				source: 'cache',
				message: `Using cached Emby user context because live fetch failed: ${err.message}`
			});
		}
		throw error(502, `Could not load Emby user context: ${err.message}`);
	}
}
