import type {NextApiRequest, NextApiResponse} from "next";
import {withIronSessionApiRoute} from "iron-session/next";
import {sessionOptions} from "@/lib/session";
import {IncomingMessage} from "http";

const ODOO_URL = process.env.ODOO_URL || "http://localhost:8069";

function buildOdooUrl(req: NextApiRequest, overridePath?: string): string {
	const path = overridePath || req.url || "/";
	const [pathname, qs] = path.split("?");
	return `${ODOO_URL}${pathname}${qs ? `?${qs}` : ""}`;
}

function collectRawBody(req: IncomingMessage): Promise<Buffer> {
	return new Promise((resolve, reject) => {
		const chunks: Buffer[] = [];
		req.on("data", (chunk: Buffer) => chunks.push(chunk));
		req.on("end", () => resolve(Buffer.concat(chunks)));
		req.on("error", reject);
	});
}

export function proxyToOdoo(overridePath?: string) {
	return withIronSessionApiRoute(async (req: NextApiRequest, res: NextApiResponse) => {
		const token = req.session.token;
		if (!token) return res.status(401).json({error: "Not authenticated"});

		const url = buildOdooUrl(req, overridePath);
		const headers: Record<string, string> = {
			Authorization: `Bearer ${token}`,
		};

		let body: string | undefined;
		if (req.method !== "GET" && req.method !== "HEAD") {
			headers["Content-Type"] = req.headers["content-type"] || "application/json";
			body = typeof req.body === "object" ? JSON.stringify(req.body) : req.body;
		}

		try {
			const resp = await fetch(url, {
				method: req.method,
				headers,
				body,
			});

			const contentType = resp.headers.get("content-type") || "";
			res.status(resp.status);

			if (contentType.includes("application/json")) {
				const data = await resp.json();
				return res.json(data);
			}

			const buffer = Buffer.from(await resp.arrayBuffer());
			res.setHeader("Content-Type", contentType);
			return res.send(buffer);
		} catch (err) {
			console.error("[odoo-proxy]", url, err);
			return res.status(502).json({error: "Backend unavailable"});
		}
	}, sessionOptions);
}

export function proxyToOdooPublic(overridePath?: string) {
	return withIronSessionApiRoute(async (req: NextApiRequest, res: NextApiResponse) => {
		const url = buildOdooUrl(req, overridePath);
		const headers: Record<string, string> = {};

		if (req.session.token) {
			headers.Authorization = `Bearer ${req.session.token}`;
		}

		let body: string | undefined;
		if (req.method !== "GET" && req.method !== "HEAD") {
			headers["Content-Type"] = req.headers["content-type"] || "application/json";
			body = typeof req.body === "object" ? JSON.stringify(req.body) : req.body;
		}

		try {
			const resp = await fetch(url, {method: req.method, headers, body});
			const contentType = resp.headers.get("content-type") || "";
			res.status(resp.status);

			if (contentType.includes("application/json")) {
				return res.json(await resp.json());
			}
			const buffer = Buffer.from(await resp.arrayBuffer());
			res.setHeader("Content-Type", contentType);
			return res.send(buffer);
		} catch (err) {
			console.error("[odoo-proxy-public]", url, err);
			return res.status(502).json({error: "Backend unavailable"});
		}
	}, sessionOptions);
}

export function proxyStreamToOdoo(overridePath?: string) {
	return withIronSessionApiRoute(async (req: NextApiRequest, res: NextApiResponse) => {
		const token = req.session.token;
		if (!token) return res.status(401).json({error: "Not authenticated"});

		const url = buildOdooUrl(req, overridePath);
		const rawBody = await collectRawBody(req);

		const headers: Record<string, string> = {
			Authorization: `Bearer ${token}`,
		};
		if (req.headers["content-type"]) {
			headers["Content-Type"] = req.headers["content-type"];
		}

		try {
			const resp = await fetch(url, {
				method: req.method || "POST",
				headers,
				body: rawBody.length > 0 ? rawBody : undefined,
			});

			const contentType = resp.headers.get("content-type") || "";
			res.status(resp.status);
			res.setHeader("Content-Type", contentType);

			if (resp.headers.get("content-disposition")) {
				res.setHeader("Content-Disposition", resp.headers.get("content-disposition")!);
			}

			const buffer = Buffer.from(await resp.arrayBuffer());
			return res.send(buffer);
		} catch (err) {
			console.error("[odoo-stream-proxy]", url, err);
			return res.status(502).json({error: "Backend unavailable"});
		}
	}, sessionOptions);
}

export {ODOO_URL};
