import { ok } from '@atcute/client';
import type { OAuthUserAgent } from '@atcute/oauth-browser-client';
import { getRpc, createAuthRpc } from './client';
import { resolveActor } from './identity';
import { parseAtUri } from './records';

export interface PublicKeyRecord {
	name: string;
	key: string;
	createdAt: string;
	rkey: string;
	uri: string;
}

export interface KnotRecord {
	domain: string;
	createdAt: string;
	rkey: string;
	uri: string;
}

export interface SpindleRecord {
	instance: string;
	createdAt: string;
	rkey: string;
	uri: string;
}

export const listPublicKeys = async (did: string): Promise<PublicKeyRecord[]> => {
	const actor = await resolveActor(did);
	const rpc = getRpc(actor.pds);
	const keys: PublicKeyRecord[] = [];
	let cursor: string | undefined;

	try {
		do {
			const page = await ok(
				rpc.get('com.atproto.repo.listRecords', {
					params: {
						repo: actor.did,
						collection: 'sh.tangled.publicKey',
						limit: 100,
						cursor,
						reverse: true,
					},
				}),
			);

			for (const r of page.records) {
				const rkey = parseAtUri(r.uri).rkey;
				const val = r.value as any;
				keys.push({
					name: val.name || '',
					key: val.key || '',
					createdAt: val.createdAt || '',
					rkey,
					uri: r.uri,
				});
			}
			cursor = page.cursor;
		} while (cursor);
	} catch (err) {
		console.error('Failed to list public keys from PDS:', err);
	}

	return keys;
};

export const addPublicKey = async (
	agent: OAuthUserAgent,
	name: string,
	key: string,
): Promise<void> => {
	const rpc = createAuthRpc(agent);
	await ok(
		rpc.post('com.atproto.repo.createRecord', {
			input: {
				repo: agent.sub,
				collection: 'sh.tangled.publicKey',
				record: {
					$type: 'sh.tangled.publicKey',
					name,
					key,
					createdAt: new Date().toISOString(),
				},
			},
		}),
	);
};

export const deletePublicKey = async (
	agent: OAuthUserAgent,
	rkey: string,
): Promise<void> => {
	const rpc = createAuthRpc(agent);
	await ok(
		rpc.post('com.atproto.repo.deleteRecord', {
			input: {
				repo: agent.sub,
				collection: 'sh.tangled.publicKey',
				rkey,
			},
		}),
	);
};

export const listKnots = async (did: string): Promise<KnotRecord[]> => {
	const actor = await resolveActor(did);
	const rpc = getRpc(actor.pds);
	const knots: KnotRecord[] = [];
	let cursor: string | undefined;

	try {
		do {
			const page = await ok(
				rpc.get('com.atproto.repo.listRecords', {
					params: {
						repo: actor.did,
						collection: 'sh.tangled.knot',
						limit: 100,
						cursor,
						reverse: true,
					},
				}),
			);

			for (const r of page.records) {
				const rkey = parseAtUri(r.uri).rkey;
				const val = r.value as any;
				knots.push({
					domain: rkey,
					createdAt: val.createdAt || '',
					rkey,
					uri: r.uri,
				});
			}
			cursor = page.cursor;
		} while (cursor);
	} catch (err) {
		console.error('Failed to list knots from PDS:', err);
	}

	return knots;
};

export const registerKnot = async (
	agent: OAuthUserAgent,
	domain: string,
): Promise<void> => {
	const rpc = createAuthRpc(agent);
	await ok(
		rpc.post('com.atproto.repo.putRecord', {
			input: {
				repo: agent.sub,
				collection: 'sh.tangled.knot',
				rkey: domain,
				record: {
					$type: 'sh.tangled.knot',
					createdAt: new Date().toISOString(),
				},
			},
		}),
	);
};

export const unregisterKnot = async (
	agent: OAuthUserAgent,
	domain: string,
): Promise<void> => {
	const rpc = createAuthRpc(agent);
	await ok(
		rpc.post('com.atproto.repo.deleteRecord', {
			input: {
				repo: agent.sub,
				collection: 'sh.tangled.knot',
				rkey: domain,
			},
		}),
	);
};

export const listSpindles = async (did: string): Promise<SpindleRecord[]> => {
	const actor = await resolveActor(did);
	const rpc = getRpc(actor.pds);
	const spindles: SpindleRecord[] = [];
	let cursor: string | undefined;

	try {
		do {
			const page = await ok(
				rpc.get('com.atproto.repo.listRecords', {
					params: {
						repo: actor.did,
						collection: 'sh.tangled.spindle',
						limit: 100,
						cursor,
						reverse: true,
					},
				}),
			);

			for (const r of page.records) {
				const rkey = parseAtUri(r.uri).rkey;
				const val = r.value as any;
				spindles.push({
					instance: rkey,
					createdAt: val.createdAt || '',
					rkey,
					uri: r.uri,
				});
			}
			cursor = page.cursor;
		} while (cursor);
	} catch (err) {
		console.error('Failed to list spindles from PDS:', err);
	}

	return spindles;
};

export const registerSpindle = async (
	agent: OAuthUserAgent,
	instance: string,
): Promise<void> => {
	const rpc = createAuthRpc(agent);
	await ok(
		rpc.post('com.atproto.repo.putRecord', {
			input: {
				repo: agent.sub,
				collection: 'sh.tangled.spindle',
				rkey: instance,
				record: {
					$type: 'sh.tangled.spindle',
					createdAt: new Date().toISOString(),
				},
			},
		}),
	);
};

export const unregisterSpindle = async (
	agent: OAuthUserAgent,
	instance: string,
): Promise<void> => {
	const rpc = createAuthRpc(agent);
	await ok(
		rpc.post('com.atproto.repo.deleteRecord', {
			input: {
				repo: agent.sub,
				collection: 'sh.tangled.spindle',
				rkey: instance,
			},
		}),
	);
};
