import { readdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, test } from "bun:test";

const LOCALES_DIR = join(import.meta.dir, "../../src/client/locales");

function flattenKeys(
	obj: Record<string, unknown>,
	prefix = "",
): string[] {
	const keys: string[] = [];
	for (const [key, value] of Object.entries(obj)) {
		const fullKey = prefix ? `${prefix}.${key}` : key;
		if (typeof value === "object" && value !== null && !Array.isArray(value)) {
			keys.push(
				...flattenKeys(value as Record<string, unknown>, fullKey),
			);
		} else {
			keys.push(fullKey);
		}
	}
	return keys.sort();
}

function loadLocale(
	locale: string,
): Record<string, Record<string, unknown>> {
	const dir = join(LOCALES_DIR, locale);
	const files = readdirSync(dir).filter((f) => f.endsWith(".json"));
	const result: Record<string, Record<string, unknown>> = {};
	for (const file of files) {
		const ns = file.replace(".json", "");
		result[ns] = JSON.parse(readFileSync(join(dir, file), "utf8"));
	}
	return result;
}

describe("locale key parity", () => {
	const en = loadLocale("en");
	const de = loadLocale("de");

	test("en and de have the same namespaces", () => {
		expect(Object.keys(en).sort()).toEqual(Object.keys(de).sort());
	});

	for (const ns of Object.keys(en)) {
		test(`${ns}: every en key exists in de`, () => {
			const enKeys = flattenKeys(en[ns]);
			const deKeys = flattenKeys(de[ns]);
			const missing = enKeys.filter((k) => !deKeys.includes(k));
			expect(missing).toEqual([]);
		});

		test(`${ns}: every de key exists in en`, () => {
			const enKeys = flattenKeys(en[ns]);
			const deKeys = flattenKeys(de[ns]);
			const orphan = deKeys.filter((k) => !enKeys.includes(k));
			expect(orphan).toEqual([]);
		});

		test(`${ns}: no empty de values`, () => {
			const deKeys = flattenKeys(de[ns]);
			for (const key of deKeys) {
				const value = key
					.split(".")
					.reduce(
						(obj, k) => (obj as Record<string, unknown>)?.[k],
						de[ns] as unknown,
					);
				expect(
					typeof value === "string" && value.length > 0,
				).toBe(true);
			}
		});
	}
});
