import { readFileSync, writeFileSync } from "fs";
import { join } from "path";

const openapiPath = join(process.cwd(), "public", "openapi.json");

console.log("Fixing OpenAPI schema...");

try {
	let openapi = JSON.parse(readFileSync(openapiPath, "utf8"));

	let unwrapped = false;
	// If the spec is nested (e.g. result.data.json from a migrated/source API), use the inner spec
	if (openapi.result?.data?.json && typeof openapi.result.data.json === "object") {
		openapi = openapi.result.data.json;
		unwrapped = true;
		console.log("✓ Unwrapped nested OpenAPI spec (result.data.json)");
	}

	let fixed = 0;
	let securityFixed = false;

	// Remove Authorization security scheme and add x-api-key
	if (!openapi.components) {
		openapi.components = {};
	}
	if (!openapi.components.securitySchemes) {
		openapi.components.securitySchemes = {};
	}

	// Remove old Authorization scheme
	if (openapi.components.securitySchemes["Authorization"]) {
		delete openapi.components.securitySchemes["Authorization"];
		securityFixed = true;
	}

	// Add x-api-key scheme
	openapi.components.securitySchemes["x-api-key"] = {
		type: "apiKey",
		in: "header",
		name: "x-api-key",
		description: "API key authentication. Use YOUR-GENERATED-API-KEY",
		"x-default": "your-key",
	};
	securityFixed = true;

	// Replace global security from Authorization to x-api-key
	if (openapi.security) {
		openapi.security = openapi.security.filter((sec) => !sec["Authorization"]);
	} else {
		openapi.security = [];
	}

	const hasApiKeySecurity = openapi.security.some((sec) => sec["x-api-key"]);
	if (!hasApiKeySecurity) {
		openapi.security.push({ "x-api-key": [] });
		securityFixed = true;
	}

	// Replace Authorization with x-api-key in all operation security
	for (const [path, pathItem] of Object.entries(openapi.paths || {})) {
		for (const [method, operation] of Object.entries(pathItem)) {
			if (operation && operation.security) {
				// Replace Authorization with x-api-key
				operation.security = operation.security.map((sec) => {
					if (sec["Authorization"] !== undefined) {
						securityFixed = true;
						return { "x-api-key": [] };
					}
					return sec;
				});
			}
		}
	}

	// Fix empty response schemas
	for (const [path, pathItem] of Object.entries(openapi.paths || {})) {
		for (const [method, operation] of Object.entries(pathItem)) {
			if (operation.responses) {
				for (const [status, response] of Object.entries(operation.responses)) {
					if (response.content && response.content["application/json"]) {
						const content = response.content["application/json"];
						// Check if schema is completely empty or missing
						if (Object.keys(content).length === 0 || !content.schema) {
							response.content["application/json"] = {
								schema: {
									type: "object",
									description: "Successful response",
								},
							};
							fixed++;
						}
					}
				}
			}
		}
	}

	if (unwrapped || fixed > 0 || securityFixed) {
		writeFileSync(openapiPath, JSON.stringify(openapi, null, 2));
		if (fixed > 0) console.log(`✓ Fixed ${fixed} empty response schemas`);
		if (securityFixed) console.log("✓ Added x-api-key security scheme");
	}

	// Keep only canonical paths (dot notation). Remove slash-aliases if present.
	let removed = 0;
	for (const pathKey of Object.keys(openapi.paths || {})) {
		if (pathKey.includes("/") && !pathKey.includes(".")) {
			const dotKey = "/" + pathKey.slice(1).replace(/\//g, ".");
			if (openapi.paths[dotKey]) {
				delete openapi.paths[pathKey];
				removed++;
			}
		}
	}
	if (removed > 0) {
		writeFileSync(openapiPath, JSON.stringify(openapi, null, 2));
		console.log(`✓ Removed ${removed} slash path alias(es), keeping dot paths only`);
	}

	if (!(unwrapped || fixed > 0 || securityFixed) && removed === 0) {
		console.log("✓ No fixes needed");
	}
} catch (error) {
	console.error("Error fixing OpenAPI schema:", error.message);
	process.exit(1);
}
