import type { BobbinContext, XrpcRequestInit } from "./client";
import { jsonGet } from "./_request";

export interface MiniDoc {
	did: string;
	handle: string;
	pds?: string;
}

export const INVALID_HANDLE = "handle.invalid";

export const resolveMiniDoc = (
	ctx: BobbinContext,
	identifier: string,
	init?: XrpcRequestInit
): Promise<MiniDoc> =>
	jsonGet<MiniDoc>(ctx, "com.bad-example.identity.resolveMiniDoc", { identifier }, init);

// did/handle cache with in-flight de-dupe.
export class IdentityCache {
	readonly #ctx: BobbinContext;
	readonly #byDid = new Map<string, MiniDoc>();
	readonly #byHandle = new Map<string, MiniDoc>();
	readonly #inflight = new Map<string, Promise<MiniDoc>>();

	constructor(ctx: BobbinContext) {
		this.#ctx = ctx;
	}

	prime(doc: MiniDoc): void {
		this.#byDid.set(doc.did, doc);
		this.#byHandle.set(doc.handle, doc);
	}

	didFor(handle: string): string | undefined {
		return this.#byHandle.get(handle)?.did;
	}

	handleFor(did: string): string | undefined {
		return this.#byDid.get(did)?.handle;
	}

	resolve(identifier: string, init?: XrpcRequestInit): Promise<MiniDoc> {
		const cached = identifier.startsWith("did:")
			? this.#byDid.get(identifier)
			: this.#byHandle.get(identifier);
		if (cached) return Promise.resolve(cached);

		const existing = this.#inflight.get(identifier);
		if (existing) return existing;

		const pending = resolveMiniDoc(this.#ctx, identifier, init)
			.then((doc) => {
				this.prime(doc);
				return doc;
			})
			.finally(() => this.#inflight.delete(identifier));
		this.#inflight.set(identifier, pending);
		return pending;
	}
}
