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

// payload types, also the keys payloads land under in the data sidecar
export const TYPE_COUNT = "sh.tangled.query.enrichResponse#count";
export const TYPE_DISTINCT_AUTHORS = "sh.tangled.query.enrichResponse#distinctAuthors";
export const TYPE_VIEWER = "sh.tangled.query.enrichResponse#viewer";
export const TYPE_MINIDOC = "com.bad-example.identity.miniDoc";

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

export interface LinkDescriptor {
	source: LinkSource;
	type: string;
	targets?: RecordPath[];
}

// data[ref][source][type] = payload, payload shape depends on the type
export type Sidecar = Record<string, Record<string, Record<string, unknown>>>;

export interface Enriched<O> {
	output: O;
	data: Sidecar;
}

export interface EnrichRequest {
	xrpc: string;
	params?: Record<string, unknown>;
	enrich: LinkDescriptor[];
	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 = (data: Sidecar, ref: string | undefined, source: LinkSource): number =>
	(ref !== undefined && (data[ref]?.[source]?.[TYPE_COUNT] as number | undefined)) || 0;

export const distinctAuthorsOf = (
	data: Sidecar,
	ref: string | undefined,
	source: LinkSource
): number =>
	(ref !== undefined && (data[ref]?.[source]?.[TYPE_DISTINCT_AUTHORS] as number | undefined)) || 0;

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

export const miniDocOf = (
	data: Sidecar,
	did: string | undefined,
	source: LinkSource
): MiniDoc | undefined =>
	did !== undefined ? (data[did]?.[source]?.[TYPE_MINIDOC] as MiniDoc | undefined) : undefined;
