import type { BobbinContext, XrpcRequestInit } from "./client";
import type { Nsid } from "@atcute/lexicons/syntax";
import { jsonPost } from "./_request";

export type RecordPath = string & {};
export type EnvelopePath = ".repo" | ".collection" | ".rkey" | ".";
export type LinkSource = `${Nsid}:${RecordPath | EnvelopePath}`;

export interface LinkDescriptor {
	source: LinkSource;
	type: "count" | "distinctAuthors" | "viewer";
}

// ref is did or at-uri, source echoes the descriptor string, viewer holds the caller's own record uri if requested, null if none exists
export interface StatsLeaf {
	count?: number;
	distinctAuthors?: number;
	viewer?: string | null;
}
export type Stats = Record<string, Record<LinkSource, StatsLeaf>>;
export interface Enriched<O> {
	output: O;
	stats: Stats;
}

export interface EnrichRequest {
	xrpc: string;
	params?: Record<string, unknown>;
	enrich: LinkDescriptor[];
	sources?: string[];
	viewer?: string;
}

export const enrich = <O>(
	ctx: BobbinContext,
	req: EnrichRequest,
	init?: XrpcRequestInit
): Promise<Enriched<O>> => jsonPost<Enriched<O>>(ctx, "sh.tangled.query.enrichResponse", req, init);

export const countOf = (stats: Stats, ref: string | undefined, source: LinkSource): number =>
	(ref !== undefined && stats[ref]?.[source]?.count) || 0;

// undefined means no viewer or inapplicable descriptor, null means no matching record
export const viewerUriOf = (
	stats: Stats,
	ref: string | undefined,
	source: LinkSource
): string | null | undefined => (ref !== undefined ? stats[ref]?.[source]?.viewer : undefined);
