import { error, redirect } from "@sveltejs/kit";
import { createBobbinClient } from "$lib/api/client";
import { resolveMiniDoc } from "$lib/api/identity";
import { getProfile, type ProfileRecord } from "$lib/api/records";
import { count } from "$lib/api/count";
import { parallel, toHttpError, httpStatusFor } from "$lib/api/load";
import { ClientResponseError } from "$lib/api/client";
import { findFollowRkey } from "$lib/api/graph";
import type { ProfileCounts } from "$lib/components/profile/types";
import type { LayoutLoad } from "./$types";

export const load: LayoutLoad = async (event) => {
	const parent = await event.parent();
	const identifier = decodeURIComponent(event.params.handle);

	// actor identifiers are dids or dotted handles; reject bare words early so
	// unrelated paths (/settings, /signup, ...) 404 instead of resolving.
	if (!identifier.startsWith("did:") && !identifier.includes(".")) {
		error(404, "Not found");
	}

	const ctx = createBobbinClient({ serviceUrl: parent.publicConfig.bobbinUrl, fetch: event.fetch });
	const doc = await resolveMiniDoc(ctx, identifier).catch((cause) =>
		toHttpError(cause, "Could not resolve user")
	);

	// canonical url is the handle; redirect dids and stale handles.
	const canonical = doc.handle && !doc.handle.endsWith(".invalid") ? doc.handle : null;
	if (canonical && identifier.toLowerCase() !== canonical.toLowerCase()) {
		redirect(307, `/${canonical}${event.url.search}`);
	}

	const did = doc.did;
	const viewerDid = parent.auth?.did;

	let profile: ProfileRecord | null = null;
	try {
		profile = (await getProfile(ctx, did)).value;
	} catch (cause) {
		if (!(cause instanceof ClientResponseError && httpStatusFor(cause) === 404)) {
			toHttpError(cause, "Could not load profile");
		}
	}

	const raw = await parallel({
		repos: count(ctx, "sh.tangled.repo.countRepos", did),
		strings: count(ctx, "sh.tangled.string.countStrings", did),
		stars: count(ctx, "sh.tangled.feed.countStarsBy", did),
		followers: count(ctx, "sh.tangled.graph.countFollows", did),
		following: count(ctx, "sh.tangled.graph.countFollowsBy", did),
		vouches: count(ctx, "sh.tangled.graph.countVouches", did),
		viewerFollowRkey:
			viewerDid && viewerDid !== did
				? findFollowRkey(ctx, viewerDid, did).catch(() => null)
				: Promise.resolve(null)
	});

	const counts: ProfileCounts = {
		repos: raw.repos.count,
		strings: raw.strings.count,
		stars: raw.stars.count,
		followers: raw.followers.count,
		following: raw.following.count,
		vouches: raw.vouches.count
	};

	const notJoined = !profile && Object.values(counts).every((n) => n === 0);

	return {
		identity: { did, handle: doc.handle, avatar: doc.avatar },
		profile,
		counts,
		viewerFollowRkey: raw.viewerFollowRkey,
		notJoined
	};
};
