import { exec, execSync } from "node:child_process";
import fs from "node:fs/promises";
import path from "node:path";
import { promisify } from "node:util";
import { TRPCError } from "@trpc/server";
import type { EstrattoContoData } from "~/server/api/routers/stripe_reports";

const execPromise = promisify(exec);
const projectRoot = path.resolve(".");
const fontsPath = path.join(projectRoot, "typst", "fonts");

const tmpDir = path.join(projectRoot, "tmp");

/**
 * Converts HTML to Typst markup using Pandoc.
 * works on Windows & Linux.
 */
export function convertHtmlToTypst(html: string): string {
	try {
		// We pass the HTML via 'input' which writes to the process stdin
		const output = execSync(
			"pandoc -f html -t typst --syntax-highlighting=none",
			{
				input: html,
				encoding: "utf-8",
			},
		);
		return output;
	} catch (error) {
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: "Failed to convert HTML to Typst",
			cause: error instanceof Error ? error : undefined,
		});
	}
}

type EstrattoContoTemplate = {
	templateId: "estratto.typ";
	data: EstrattoContoData;
};
export type RicevutaProps = {
	ordineId: string;
	date: string;
	datetime: string;
	nominativo: string;
	codicefiscale: string;
	indirizzo: string;
	nazione: string;
	items: {
		title: string;
		desc: string | null;
		discount: number | null;
		amount: number;
		strike: boolean;
	}[];
	total: number;
	vat: number;
	method: string;
};
type RicevutaTemplate = {
	templateId: "receipt.typ";
	data: RicevutaProps;
};

type TestiTemplate = {
	templateId: "testi.typ";
	data: {
		/**
		 * const striga = convertHtmlToTypst(stringa_value);
		 */
		stringa: string;
	};
};
export type AnnuncioTemplateData = {
	codice: string;
	nominativo: string;
	numero: string;
	indirizzo: string;
	lat: string;
	lon: string;
	tipo: string;
	prezzo: number;
	titolo_it: string;
	desc_it: string;
	disponibile_da: string;
	caratteristiche: [string, string][];
};
type AnnuncioTemplate = {
	templateId: "annuncio.typ";
	data: AnnuncioTemplateData;
};
type TypstInput =
	| EstrattoContoTemplate
	| RicevutaTemplate
	| TestiTemplate
	| AnnuncioTemplate;

export const TypstGenerate = async ({ templateId, data }: TypstInput) => {
	const timestamp = Date.now();
	await fs.mkdir(tmpDir, { recursive: true });
	const tmpDataFile = `data-${timestamp}.json`;
	const tmpDataPath = path.join(tmpDir, tmpDataFile);
	const templatePath = path.join(projectRoot, "typst", templateId);
	const resultPath = path.join(tmpDir, `doc-${timestamp}.pdf`);

	await fs.writeFile(tmpDataPath, JSON.stringify(data));

	try {
		const command = `typst compile --input data_path=/tmp/${tmpDataFile} --root "${projectRoot}" --font-path "${fontsPath}" "${templatePath}" "${resultPath}"`;

		await execPromise(command);

		return await fs.readFile(resultPath);
	} catch (err) {
		console.error(`typst compile failed, template: ${templateId}:`, err);
		throw new TRPCError({
			code: "INTERNAL_SERVER_ERROR",
			message: `Failed to generate PDF with Typst, template: ${templateId}`,
			cause: err instanceof Error ? err : undefined,
		});
	} finally {
		await Promise.all([
			fs.unlink(tmpDataPath).catch(() => {}),
			fs.unlink(resultPath).catch(() => {}),
		]);
	}
};
