import fetch from "node-fetch";
import { Converter } from "opencc-js";
import { getAgentByUrl } from "@/misc/fetch.js";
import { fetchMeta } from "backend-rs";
import type { PostLanguage } from "@/misc/langmap";
import * as deepl from "deepl-node";

// DeepL translate and LibreTranslate don't provide
// zh-Hant-TW translations, so we convert zh-Hans-CN
// translations into zh-Hant-TW using opencc-js.
function convertChinese(convert: boolean, src: string) {
	if (!convert) return src;
	const converter = Converter({ from: "cn", to: "twp" });
	return converter(src);
}

function stem(lang: PostLanguage): string {
	let toReturn = lang as string;
	if (toReturn.includes("-")) toReturn = toReturn.split("-")[0];
	if (toReturn.includes("_")) toReturn = toReturn.split("_")[0];
	return toReturn;
}

export async function translate(
	text: string,
	from: PostLanguage | null,
	to: PostLanguage,
) {
	const instance = await fetchMeta(true);

	if (instance.deeplAuthKey == null && instance.libreTranslateApiUrl == null) {
		throw Error("No translator is set up on this server.");
	}

	const source = from == null ? null : stem(from);
	const target = stem(to);

	if (instance.libreTranslateApiUrl != null) {
		const jsonBody = {
			q: text,
			source: source ?? "auto",
			target,
			format: "text",
			api_key: instance.libreTranslateApiKey ?? "",
		};

		const url = new URL(instance.libreTranslateApiUrl);
		if (url.pathname.endsWith("/")) {
			url.pathname = url.pathname.slice(0, -1);
		}
		if (!url.pathname.endsWith("/translate")) {
			url.pathname += "/translate";
		}
		const res = await fetch(url.toString(), {
			method: "POST",
			headers: {
				"Content-Type": "application/json",
			},
			body: JSON.stringify(jsonBody),
			agent: getAgentByUrl,
		});

		const json = (await res.json()) as {
			detectedLanguage?: {
				confidence: number;
				language: string;
			};
			translatedText: string;
		};

		return {
			sourceLang: source ?? json.detectedLanguage?.language,
			text: convertChinese(
				["zh-hant", "zh-TW"].includes(to),
				json.translatedText,
			),
		};
	}

	const deeplTranslator = new deepl.Translator(instance.deeplAuthKey ?? "");
	const result = await deeplTranslator.translateText(
		text,
		source as deepl.SourceLanguageCode | null,
		// DeepL API requires us to specify "en-US" or "en-GB" for English
		// translations ("en" does not work), so we need to address it
		(target === "en" ? to : target) as deepl.TargetLanguageCode,
	);

	return {
		sourceLang: source ?? result.detectedSourceLang,
		text: convertChinese(["zh-hant", "zh-TW"].includes(to), result.text),
	};
}
