import { PrismaClient } from "@prisma/client";
import express from "express";
import { env } from "node:process";
import axios from "axios";
import { GithubClient } from "./github";
import { z } from "zod";

const db = new PrismaClient();

// Map to store worker addresses by project ID
const workers = new Map<number, string[]>();
const logs = new Map<number, Map<string, string>>();

const handleProjectCreate: express.Handler = async (req, resp) => {
	try {
		const { id } = await db.project.create({
			data: {
				userId: resp.locals.userId,
				name: req.body.name,
			},
		});
		resp.status(200);
		resp.header("Content-Type", "application/json");
		resp.write(
			JSON.stringify({
				id,
			}),
		);
	} catch (e) {
		console.log(e);
		resp.status(500);
	} finally {
		resp.end();
	}
};

const handleProjectAll: express.Handler = async (req, resp) => {
	try {
		const r = await db.project.findMany({
			where: {
				userId: resp.locals.userId,
			},
		});
		resp.status(200);
		resp.header("Content-Type", "application/json");
		resp.write(
			JSON.stringify(
				r.map((p) => ({
					id: p.id.toString(),
					name: p.name,
				})),
			),
		);
	} catch (e) {
		console.log(e);
		resp.status(500);
	} finally {
		resp.end();
	}
};

const handleSave: express.Handler = async (req, resp) => {
	try {
		await db.project.update({
			where: {
				id: Number(req.params["projectId"]),
				userId: resp.locals.userId,
			},
			data: {
				draft: Buffer.from(JSON.stringify(req.body)),
			},
		});
		resp.status(200);
	} catch (e) {
		console.log(e);
		resp.status(500);
	} finally {
		resp.end();
	}
};

function handleSavedGet(state: "deploy" | "draft"): express.Handler {
	return async (req, resp) => {
		try {
			const r = await db.project.findUnique({
				where: {
					id: Number(req.params["projectId"]),
					userId: resp.locals.userId,
				},
				select: {
					state: true,
					draft: true,
				},
			});
			if (r == null) {
				resp.status(404);
				return;
			}
			resp.status(200);
			resp.header("content-type", "application/json");
			if (state === "deploy") {
				if (r.state == null) {
					resp.send({
						nodes: [],
						edges: [],
						viewport: { x: 0, y: 0, zoom: 1 },
					});
				} else {
					resp.send(JSON.parse(Buffer.from(r.state).toString("utf8")));
				}
			} else {
				if (r.draft == null) {
					if (r.state == null) {
						resp.send({
							nodes: [],
							edges: [],
							viewport: { x: 0, y: 0, zoom: 1 },
						});
					} else {
						resp.send(JSON.parse(Buffer.from(r.state).toString("utf8")));
					}
				} else {
					resp.send(JSON.parse(Buffer.from(r.draft).toString("utf8")));
				}
			}
		} catch (e) {
			console.log(e);
			resp.status(500);
		} finally {
			resp.end();
		}
	};
}

const handleDelete: express.Handler = async (req, resp) => {
	try {
		const projectId = Number(req.params["projectId"]);
		const p = await db.project.findUnique({
			where: {
				id: projectId,
				userId: resp.locals.userId,
			},
			select: {
				instanceId: true,
			},
		});
		if (p === null) {
			resp.status(404);
			return;
		}
		const r = await axios.request({
			url: `http://appmanager.hgrz-appmanager.svc.cluster.local/api/instance/${p.instanceId}/remove`,
			method: "post",
		});
		if (r.status === 200) {
			await db.project.delete({
				where: {
					id: projectId,
				},
			});
		}
		resp.status(200);
	} catch (e) {
		console.log(e);
		resp.status(500);
	} finally {
		resp.end();
	}
};

const handleDeploy: express.Handler = async (req, resp) => {
	try {
		const projectId = Number(req.params["projectId"]);
		const state = Buffer.from(JSON.stringify(req.body.state));
		const p = await db.project.findUnique({
			where: {
				id: projectId,
				userId: resp.locals.userId,
			},
			select: {
				instanceId: true,
				githubToken: true,
				deployKey: true,
			},
		});
		if (p === null) {
			resp.status(404);
			return;
		}
		await db.project.update({
			where: {
				id: projectId,
			},
			data: {
				draft: state,
			},
		});
		let r: { status: number; data: { id: string; deployKey: string } };
		if (p.instanceId == null) {
			r = await axios.request({
				url: "http://appmanager.hgrz-appmanager.svc.cluster.local/api/dodo-app",
				method: "post",
				data: {
					config: req.body.config,
				},
			});
			if (r.status === 200) {
				await db.project.update({
					where: {
						id: projectId,
					},
					data: {
						state,
						draft: null,
						instanceId: r.data.id,
						deployKey: r.data.deployKey,
					},
				});

				if (p.githubToken && r.data.deployKey) {
					const stateObj = JSON.parse(JSON.parse(state.toString()));
					const githubNodes = stateObj.nodes.filter(
						// eslint-disable-next-line @typescript-eslint/no-explicit-any
						(n: any) => n.type === "github" && n.data?.repository?.id,
					);

					const github = new GithubClient(p.githubToken);
					for (const node of githubNodes) {
						try {
							await github.addDeployKey(node.data.repository.sshURL, r.data.deployKey);
						} catch (error) {
							console.error(
								`Failed to add deploy key to repository ${node.data.repository.sshURL}:`,
								error,
							);
						}
					}
				}
			}
		} else {
			r = await axios.request({
				url: `http://appmanager.hgrz-appmanager.svc.cluster.local/api/dodo-app/${p.instanceId}`,
				method: "put",
				data: {
					config: req.body.config,
				},
			});
			if (r.status === 200) {
				await db.project.update({
					where: {
						id: projectId,
					},
					data: {
						state,
						draft: null,
					},
				});
			}
		}
	} catch (e) {
		console.log(e);
		resp.status(500);
	} finally {
		resp.end();
	}
};

const handleStatus: express.Handler = async (req, resp) => {
	try {
		const projectId = Number(req.params["projectId"]);
		const p = await db.project.findUnique({
			where: {
				id: projectId,
				userId: resp.locals.userId,
			},
			select: {
				instanceId: true,
			},
		});
		if (p === null) {
			resp.status(404);
			return;
		}
		if (p.instanceId == null) {
			resp.status(404);
			return;
		}
		const r = await axios.request({
			url: `http://appmanager.hgrz-appmanager.svc.cluster.local/api/instance/${p.instanceId}/status`,
			method: "get",
		});
		resp.status(r.status);
		if (r.status === 200) {
			resp.write(JSON.stringify(r.data));
		}
	} catch (e) {
		console.log(e);
		resp.status(500);
	} finally {
		resp.end();
	}
};

const handleGithubRepos: express.Handler = async (req, resp) => {
	try {
		const projectId = Number(req.params["projectId"]);
		const project = await db.project.findUnique({
			where: {
				id: projectId,
				userId: resp.locals.userId,
			},
			select: {
				githubToken: true,
			},
		});

		if (!project?.githubToken) {
			resp.status(400);
			resp.write(JSON.stringify({ error: "GitHub token not configured" }));
			return;
		}

		const github = new GithubClient(project.githubToken);
		const repositories = await github.getRepositories();

		resp.status(200);
		resp.header("Content-Type", "application/json");
		resp.write(JSON.stringify(repositories));
	} catch (e) {
		console.log(e);
		resp.status(500);
		resp.write(JSON.stringify({ error: "Failed to fetch repositories" }));
	} finally {
		resp.end();
	}
};

const handleUpdateGithubToken: express.Handler = async (req, resp) => {
	try {
		const projectId = Number(req.params["projectId"]);
		const { githubToken } = req.body;

		await db.project.update({
			where: {
				id: projectId,
				userId: resp.locals.userId,
			},
			data: { githubToken },
		});

		resp.status(200);
	} catch (e) {
		console.log(e);
		resp.status(500);
	} finally {
		resp.end();
	}
};

const handleEnv: express.Handler = async (req, resp) => {
	const projectId = Number(req.params["projectId"]);
	try {
		const project = await db.project.findUnique({
			where: {
				id: projectId,
				userId: resp.locals.userId,
			},
			select: {
				deployKey: true,
				githubToken: true,
			},
		});

		if (!project) {
			resp.status(404);
			resp.write(JSON.stringify({ error: "Project not found" }));
			return;
		}

		const projectLogs = logs.get(projectId) || new Map();
		const services = Array.from(projectLogs.keys());

		resp.status(200);
		resp.write(
			JSON.stringify({
				// TODO(gio): get from env or command line flags
				managerAddr: "http://10.42.0.211:8081",
				deployKey: project.deployKey,
				integrations: {
					github: !!project.githubToken,
				},
				networks: [
					{
						name: "Public",
						domain: "v1.dodo.cloud",
					},
					{
						name: "Private",
						domain: "p.v1.dodo.cloud",
					},
				],
				services,
			}),
		);
	} catch (error) {
		console.error("Error checking integrations:", error);
		resp.status(500);
		resp.write(JSON.stringify({ error: "Internal server error" }));
	} finally {
		resp.end();
	}
};

const handleServiceLogs: express.Handler = async (req, resp) => {
	try {
		const projectId = Number(req.params["projectId"]);
		const service = req.params["service"];
		const project = await db.project.findUnique({
			where: {
				id: projectId,
				userId: resp.locals.userId,
			},
		});
		if (project == null) {
			resp.status(404);
			resp.write(JSON.stringify({ error: "Project not found" }));
			return;
		}

		const projectLogs = logs.get(projectId);
		if (!projectLogs) {
			resp.status(404);
			resp.write(JSON.stringify({ error: "No logs found for this project" }));
			return;
		}

		const serviceLog = projectLogs.get(service);
		if (!serviceLog) {
			resp.status(404);
			resp.write(JSON.stringify({ error: "No logs found for this service" }));
			return;
		}

		resp.status(200);
		resp.write(JSON.stringify({ logs: serviceLog }));
	} catch (e) {
		console.log(e);
		resp.status(500);
		resp.write(JSON.stringify({ error: "Failed to get service logs" }));
	} finally {
		resp.end();
	}
};

const WorkerSchema = z.object({
	service: z.string(),
	address: z.string().url(),
	logs: z.optional(z.string()),
});

const handleRegisterWorker: express.Handler = async (req, resp) => {
	try {
		const projectId = Number(req.params["projectId"]);

		const result = WorkerSchema.safeParse(req.body);
		if (!result.success) {
			resp.status(400);
			resp.write(
				JSON.stringify({
					error: "Invalid request data",
					details: result.error.format(),
				}),
			);
			return;
		}

		const { service, address, logs: log } = result.data;

		// Get existing workers or initialize empty array
		const projectWorkers = workers.get(projectId) || [];

		// Add new worker if not already present
		if (!projectWorkers.includes(address)) {
			projectWorkers.push(address);
		}

		workers.set(projectId, projectWorkers);
		if (log) {
			const svcLogs: Map<string, string> = logs.get(projectId) || new Map();
			svcLogs.set(service, log);
			logs.set(projectId, svcLogs);
		}
		resp.status(200);
		resp.write(
			JSON.stringify({
				success: true,
			}),
		);
	} catch (e) {
		console.log(e);
		resp.status(500);
		resp.write(JSON.stringify({ error: "Failed to register worker" }));
	} finally {
		resp.end();
	}
};

const handleReload: express.Handler = async (req, resp) => {
	try {
		const projectId = Number(req.params["projectId"]);
		const projectWorkers = workers.get(projectId) || [];
		const project = await db.project.findUnique({
			where: {
				id: projectId,
				userId: resp.locals.userId,
			},
		});
		if (project == null) {
			resp.status(404);
			resp.write(JSON.stringify({ error: "Project not found" }));
			return;
		}

		if (projectWorkers.length === 0) {
			resp.status(404);
			resp.write(JSON.stringify({ error: "No workers registered for this project" }));
			return;
		}

		await Promise.all(
			projectWorkers.map(async (workerAddress) => {
				try {
					const updateEndpoint = `${workerAddress}/update`;
					await axios.post(updateEndpoint);
					// eslint-disable-next-line @typescript-eslint/no-explicit-any
				} catch (error: any) {
					console.log(`Failed to update worker ${workerAddress}: ${error.message || "Unknown error"}`);
				}
			}),
		);

		resp.status(200);
		resp.write(JSON.stringify({ success: true }));
	} catch (e) {
		console.log(e);
		resp.status(500);
		resp.write(JSON.stringify({ error: "Failed to reload workers" }));
	} finally {
		resp.end();
	}
};

const auth = (req: express.Request, resp: express.Response, next: express.NextFunction) => {
	const userId = req.get("x-forwarded-userid");
	if (userId === undefined) {
		resp.status(401);
		resp.write("Unauthorized");
		resp.end();
		return;
	}
	resp.locals.userId = userId;
	next();
};

async function start() {
	await db.$connect();
	const app = express();
	app.use(express.json());
	app.use(auth);
	app.post("/api/project/:projectId/saved", handleSave);
	app.get("/api/project/:projectId/saved/deploy", handleSavedGet("deploy"));
	app.get("/api/project/:projectId/saved/draft", handleSavedGet("draft"));
	app.post("/api/project/:projectId/deploy", handleDeploy);
	app.get("/api/project/:projectId/status", handleStatus);
	app.delete("/api/project/:projectId", handleDelete);
	app.get("/api/project", handleProjectAll);
	app.post("/api/project", handleProjectCreate);
	app.get("/api/project/:projectId/repos/github", handleGithubRepos);
	app.post("/api/project/:projectId/github-token", handleUpdateGithubToken);
	app.get("/api/project/:projectId/env", handleEnv);
	app.post("/api/project/:projectId/reload", handleReload);
	app.get("/api/project/:projectId/logs/:service", handleServiceLogs);
	app.use("/", express.static("../front/dist"));

	const api = express();
	api.use(express.json());
	api.post("/api/project/:projectId/workers", handleRegisterWorker);

	// Start both servers
	app.listen(env.DODO_PORT_WEB, () => {
		console.log("Web server started on port", env.DODO_PORT_WEB);
	});

	api.listen(env.DODO_PORT_API, () => {
		console.log("Internal API server started on port", env.DODO_PORT_API);
	});
}

start();
