import type { BobbinContext, XrpcRequestInit } from "./client";
import { jsonGet } from "./_request";
import type * as ShTangledActorProfile from "./lexicons/types/sh/tangled/actor/profile";
import type * as ShTangledFeedComment from "./lexicons/types/sh/tangled/feed/comment";
import type * as ShTangledRepo from "./lexicons/types/sh/tangled/repo";
import type * as ShTangledRepoIssue from "./lexicons/types/sh/tangled/repo/issue";
import type * as ShTangledRepoIssueState from "./lexicons/types/sh/tangled/repo/issue/state";
import type * as ShTangledRepoPull from "./lexicons/types/sh/tangled/repo/pull";
import type * as ShTangledString from "./lexicons/types/sh/tangled/string";

export interface RecordView<V> {
	uri: string;
	cid?: string;
	value: V;
}

export interface RecordList<V> {
	items: RecordView<V>[];
}

export type RepoRecord = ShTangledRepo.Main;
export type ProfileRecord = ShTangledActorProfile.Main;
export type IssueRecord = ShTangledRepoIssue.Main;
export type IssueStateRecord = ShTangledRepoIssueState.Main;
export type PullRecord = ShTangledRepoPull.Main;
export type StringRecord = ShTangledString.Main;
export type CommentRecord = ShTangledFeedComment.Main;

export const BULK_LIMIT = 50;

export const getRepo = (ctx: BobbinContext, repo: string, init?: XrpcRequestInit) =>
	jsonGet<RecordView<RepoRecord>>(ctx, "sh.tangled.repo.getRepo", { repo }, init);

export const getRepoByRepoDid = (ctx: BobbinContext, repoDid: string, init?: XrpcRequestInit) =>
	jsonGet<RecordView<RepoRecord>>(ctx, "sh.tangled.repo.getRepoByRepoDid", { repoDid }, init);

export const getRepoByName = (
	ctx: BobbinContext,
	owner: string,
	name: string,
	init?: XrpcRequestInit
) => jsonGet<RecordView<RepoRecord>>(ctx, "sh.tangled.repo.getRepoByName", { owner, name }, init);

export const getProfile = (ctx: BobbinContext, did: string, init?: XrpcRequestInit) =>
	jsonGet<RecordView<ProfileRecord>>(
		ctx,
		"sh.tangled.actor.getProfile",
		{ actor: `at://${did}/sh.tangled.actor.profile/self` },
		init
	);

export const getIssue = (ctx: BobbinContext, issue: string, init?: XrpcRequestInit) =>
	jsonGet<RecordView<IssueRecord>>(ctx, "sh.tangled.repo.getIssue", { issue }, init);

export type IssueState = "open" | "closed";

// a listIssues row: the embedded issue record plus bobbin-derived state/counts.
export interface IssueListItem {
	cid?: string;
	commentCount: number;
	state: string;
	stateUpdatedAt?: string;
	uri: string;
	value: IssueRecord;
}

export interface IssueListPage {
	cursor?: string | null;
	items: IssueListItem[];
}

export interface ListIssuesFilter {
	state?: IssueState;
	author?: string;
	limit?: number;
	cursor?: string;
	order?: "asc" | "desc";
}

export const listIssues = (
	ctx: BobbinContext,
	subject: string,
	filter: ListIssuesFilter = {},
	init?: XrpcRequestInit
) => jsonGet<IssueListPage>(ctx, "sh.tangled.repo.listIssues", { subject, ...filter }, init);

// getIssue returns the raw record only; the derived open/closed state lives in
// separate sh.tangled.repo.issue.state records, latest-wins.
export interface IssueStateList {
	cursor?: string | null;
	items: RecordView<IssueStateRecord>[];
}

export const listIssueStates = (
	ctx: BobbinContext,
	subject: string,
	filter: { limit?: number; cursor?: string; order?: "asc" | "desc" } = {},
	init?: XrpcRequestInit
) => jsonGet<IssueStateList>(ctx, "sh.tangled.repo.issue.listStates", { subject, ...filter }, init);

// comments on any record (issue/pull/string) are flat sh.tangled.feed.comment records;
// threading is derived client-side from each comment's optional replyTo strongRef.
export interface CommentListPage {
	cursor?: string | null;
	items: RecordView<CommentRecord>[];
}

export const listComments = (
	ctx: BobbinContext,
	subject: string,
	filter: { limit?: number; cursor?: string; order?: "asc" | "desc" } = {},
	init?: XrpcRequestInit
) => jsonGet<CommentListPage>(ctx, "sh.tangled.feed.listComments", { subject, ...filter }, init);

export const getPull = (ctx: BobbinContext, pull: string, init?: XrpcRequestInit) =>
	jsonGet<RecordView<PullRecord>>(ctx, "sh.tangled.repo.getPull", { pull }, init);

export const getRepos = (ctx: BobbinContext, repos: readonly string[], init?: XrpcRequestInit) =>
	jsonGet<RecordList<RepoRecord>>(ctx, "sh.tangled.repo.getRepos", { repos }, init);

export const getReposByRepoDids = (
	ctx: BobbinContext,
	dids: readonly string[],
	init?: XrpcRequestInit
) => jsonGet<RecordList<RepoRecord>>(ctx, "sh.tangled.repo.getReposByRepoDids", { dids }, init);

export const getProfiles = (
	ctx: BobbinContext,
	actors: readonly string[],
	init?: XrpcRequestInit
) => jsonGet<RecordList<ProfileRecord>>(ctx, "sh.tangled.actor.getProfiles", { actors }, init);

export const getIssues = (ctx: BobbinContext, issues: readonly string[], init?: XrpcRequestInit) =>
	jsonGet<RecordList<IssueRecord>>(ctx, "sh.tangled.repo.getIssues", { issues }, init);

export const getPulls = (ctx: BobbinContext, pulls: readonly string[], init?: XrpcRequestInit) =>
	jsonGet<RecordList<PullRecord>>(ctx, "sh.tangled.repo.getPulls", { pulls }, init);
