import axios from "axios";
import { z } from "zod";

export const GithubRepositorySchema = z.object({
	id: z.number(),
	name: z.string(),
	full_name: z.string(),
	html_url: z.string(),
	ssh_url: z.string(),
});

const DeployKeysSchema = z.array(
	z.object({
		id: z.number(),
		key: z.string(),
	}),
);

const WebhookSchema = z.object({
	id: z.number(),
	config: z.object({
		url: z.string().optional(), // url might not always be present
		content_type: z.string().optional(),
	}),
	events: z.array(z.string()),
	active: z.boolean(),
});

const ListWebhooksResponseSchema = z.array(WebhookSchema);

export type GithubRepository = z.infer<typeof GithubRepositorySchema>;

export class GithubClient {
	private token: string;

	constructor(token: string) {
		this.token = token;
	}

	private getHeaders() {
		return {
			Authorization: `Bearer ${this.token}`,
			Accept: "application/vnd.github.v3+json",
			"X-GitHub-Api-Version": "2022-11-28",
		};
	}

	async getRepositories(): Promise<GithubRepository[]> {
		const response = await axios.get("https://api.github.com/user/repos", {
			headers: this.getHeaders(),
		});
		return z.array(GithubRepositorySchema).parse(response.data);
	}

	async addDeployKey(repoPath: string, key: string) {
		const sshUrl = repoPath;
		const repoOwnerAndName = sshUrl.replace("git@github.com:", "").replace(".git", "");
		let existingKeys: z.infer<typeof DeployKeysSchema> = [];
		const response = await axios.get(`https://api.github.com/repos/${repoOwnerAndName}/keys`, {
			headers: this.getHeaders(),
		});
		const parsedResult = DeployKeysSchema.safeParse(response.data);
		if (parsedResult.success) {
			existingKeys = parsedResult.data;
		} else {
			console.error("Failed to parse existing deploy keys:", parsedResult.error);
		}
		const keyToAddParts = key.trim().split(" ");
		const mainKeyPartToAdd = keyToAddParts.length > 1 ? keyToAddParts.slice(0, 2).join(" ") : key.trim();
		const keyAlreadyExists = existingKeys.some((existingKeyObj) => {
			const existingKeyParts = existingKeyObj.key.trim().split(" ");
			const mainExistingKeyPart =
				existingKeyParts.length > 1 ? existingKeyParts.slice(0, 2).join(" ") : existingKeyObj.key.trim();
			return mainExistingKeyPart === mainKeyPartToAdd;
		});
		if (keyAlreadyExists) {
			return;
		}
		await axios.post(
			`https://api.github.com/repos/${repoOwnerAndName}/keys`,
			{
				title: "dodo",
				key: key,
				read_only: true,
			},
			{
				headers: this.getHeaders(),
			},
		);
	}

	async removeDeployKey(repoPath: string, key: string) {
		const sshUrl = repoPath;
		const repoOwnerAndName = sshUrl.replace("git@github.com:", "").replace(".git", "");
		const response = await axios.get(`https://api.github.com/repos/${repoOwnerAndName}/keys`, {
			headers: this.getHeaders(),
		});
		const result = DeployKeysSchema.safeParse(response.data);
		if (!result.success) {
			console.error("Failed to parse deploy keys response for removal:", result.error);
			// Depending on desired robustness, you might throw an error or return early.
			// For now, if parsing fails, we can't identify keys to remove.
			throw new Error("Failed to parse deploy keys response during removal process");
		}

		// Extract the main part of the key we intend to remove
		const keyToRemoveParts = key.trim().split(" ");
		const mainKeyPartToRemove = keyToRemoveParts.length > 1 ? keyToRemoveParts.slice(0, 2).join(" ") : key.trim();

		const deployKeysToDelete = result.data.filter((existingKeyObj) => {
			const existingKeyParts = existingKeyObj.key.trim().split(" ");
			const mainExistingKeyPart =
				existingKeyParts.length > 1 ? existingKeyParts.slice(0, 2).join(" ") : existingKeyObj.key.trim();
			return mainExistingKeyPart === mainKeyPartToRemove;
		});

		if (deployKeysToDelete.length === 0) {
			console.log(
				`No deploy key matching '${mainKeyPartToRemove.substring(0, 50)}...' found in repo ${repoOwnerAndName} for removal.`,
			);
			return;
		}

		await Promise.all(
			deployKeysToDelete.map((deployKey) => {
				console.log(
					`Removing deploy key ID ${deployKey.id} ('${deployKey.key.substring(0, 50)}...') from repo ${repoOwnerAndName}`,
				);
				return axios.delete(`https://api.github.com/repos/${repoOwnerAndName}/keys/${deployKey.id}`, {
					headers: this.getHeaders(),
				});
			}),
		);
		console.log(
			`Successfully initiated removal of ${deployKeysToDelete.length} matching deploy key(s) from ${repoOwnerAndName}.`,
		);
	}

	async addPushWebhook(repoPath: string, callbackAddress: string): Promise<boolean> {
		const repoOwnerAndName = repoPath.replace("git@github.com:", "").replace(".git", "");
		const resp = await axios.post(
			`https://api.github.com/repos/${repoOwnerAndName}/hooks`,
			{
				name: "web",
				active: true,
				events: ["push"],
				config: {
					url: callbackAddress,
					content_type: "json",
				},
			},
			{
				headers: this.getHeaders(),
			},
		);
		return resp.status === 201;
	}

	async removePushWebhook(repoPath: string, callbackAddress: string): Promise<boolean> {
		const repoOwnerAndName = repoPath.replace("git@github.com:", "").replace(".git", "");
		const listHooksUrl = `https://api.github.com/repos/${repoOwnerAndName}/hooks`;
		try {
			const response = await axios.get(listHooksUrl, {
				headers: this.getHeaders(),
			});
			const parsedHooks = ListWebhooksResponseSchema.safeParse(response.data);
			if (!parsedHooks.success) {
				throw new Error(`Failed to parse webhooks list for ${repoOwnerAndName}`);
			}
			const results = await Promise.all(
				parsedHooks.data
					.filter((hook) => hook.config.url === callbackAddress && hook.events.includes("push"))
					.map(async (hook) => {
						const deleteHookUrl = `https://api.github.com/repos/${repoOwnerAndName}/hooks/${hook.id}`;
						const resp = await axios.delete(deleteHookUrl, { headers: this.getHeaders() });
						return resp.status === 204;
					}),
			);
			return results.reduce((acc, curr) => acc && curr, true);
			// eslint-disable-next-line @typescript-eslint/no-explicit-any
		} catch (error: any) {
			console.error(
				`Failed to list or remove webhooks for ${repoOwnerAndName}:`,
				error.response?.data || error.message,
			);
			throw error; // Re-throw to let the caller handle it
		}
	}
}
