import { ok } from "@atcute/client";
import { now as tidNow } from "@atcute/tid";
import { mainSchema as createRecordSchema } from "@atcute/atproto/types/repo/createRecord";
import { mainSchema as deleteRecordSchema } from "@atcute/atproto/types/repo/deleteRecord";
import type { Nsid, RecordKey } from "@atcute/lexicons/syntax";
import type { OAuthUserAgent } from "@atcute/oauth-browser-client";
import { createClient } from "$lib/auth/agent";
import { jsonGet } from "./_request";
import type { BobbinContext, XrpcRequestInit } from "./client";
import { rkeyFromUri } from "./uri";
import type * as ShTangledPublicKey from "./lexicons/types/sh/tangled/publicKey";

export type PublicKeyRecord = ShTangledPublicKey.Main;

const PUBLIC_KEY_COLLECTION = "sh.tangled.publicKey" as Nsid;

export interface ListedRecord<V> {
	uri: string;
	rkey: string;
	value: V;
}

interface ListResponse {
	cursor?: string;
	items: { uri: string; cid?: string; value: unknown }[];
}

const listRecords = async <V>(
	ctx: BobbinContext,
	nsid: string,
	did: string,
	init?: XrpcRequestInit
): Promise<ListedRecord<V>[]> => {
	const res = await jsonGet<ListResponse>(ctx, nsid, { subject: did }, init);
	return res.items.map((item) => ({
		uri: item.uri,
		rkey: rkeyFromUri(item.uri),
		value: item.value as V
	}));
};

export const listPubKeys = (ctx: BobbinContext, did: string, init?: XrpcRequestInit) =>
	listRecords<PublicKeyRecord>(ctx, "sh.tangled.publicKey.listKeys", did, init);

export const createPubKey = async (
	agent: OAuthUserAgent,
	name: string,
	key: string
): Promise<string> => {
	const rpc = createClient(agent);
	// the client mints the rkey (a TID) rather than letting the PDS assign one.
	const rkey = tidNow();
	await ok(
		rpc.call(createRecordSchema, {
			input: {
				repo: agent.sub,
				collection: PUBLIC_KEY_COLLECTION,
				rkey: rkey as RecordKey,
				record: {
					$type: "sh.tangled.publicKey",
					name,
					key,
					createdAt: new Date().toISOString()
				}
			}
		})
	);
	return rkey;
};

export const deletePubKey = async (agent: OAuthUserAgent, rkey: string): Promise<void> => {
	const rpc = createClient(agent);
	await ok(
		rpc.call(deleteRecordSchema, {
			input: { repo: agent.sub, collection: PUBLIC_KEY_COLLECTION, rkey: rkey as RecordKey }
		})
	);
};
