#!/usr/bin/env node

const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const axios = require('axios');

const PERMISSIONS_TYPE_FILE = path.join(
	__dirname,
	'../src/hooks/useAuthZ/permissions.type.ts',
);

const SIGNOZ_INTEGRATION_IMAGE = 'signoz:integration';
const LOCAL_BACKEND_URL = 'http://localhost:8080';

function log(message) {
	console.log(`[generate-permissions-type] ${message}`);
}

function getBackendUrlFromDocker() {
	try {
		const output = execSync(
			`docker ps --filter "ancestor=${SIGNOZ_INTEGRATION_IMAGE}" --format "{{.Ports}}"`,
			{ encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] },
		).trim();

		if (!output) {
			return null;
		}

		const portMatch = output.match(/0\.0\.0\.0:(\d+)->8080\/tcp/);
		if (portMatch) {
			return `http://localhost:${portMatch[1]}`;
		}

		const ipv6Match = output.match(/:::(\d+)->8080\/tcp/);
		if (ipv6Match) {
			return `http://localhost:${ipv6Match[1]}`;
		}
	} catch (err) {
		log(`Warning: Could not get port from docker: ${err.message}`);
	}
	return null;
}

async function checkBackendHealth(url, maxAttempts = 3, delayMs = 1000) {
	for (let attempt = 1; attempt <= maxAttempts; attempt++) {
		try {
			await axios.get(`${url}/api/v1/health`, {
				timeout: 5000,
				validateStatus: (status) => status === 200,
			});
			return true;
		} catch (err) {
			if (attempt < maxAttempts) {
				await new Promise((r) => setTimeout(r, delayMs));
			}
		}
	}
	return false;
}

async function discoverBackendUrl() {
	const dockerUrl = getBackendUrlFromDocker();
	if (dockerUrl) {
		log(`Found ${SIGNOZ_INTEGRATION_IMAGE} container, trying ${dockerUrl}...`);
		if (await checkBackendHealth(dockerUrl)) {
			log(`Backend found at ${dockerUrl} (from py-test-setup)`);
			return dockerUrl;
		}
		log(`Backend at ${dockerUrl} is not responding`);
	}

	log(`Trying local backend at ${LOCAL_BACKEND_URL}...`);
	if (await checkBackendHealth(LOCAL_BACKEND_URL)) {
		log(`Backend found at ${LOCAL_BACKEND_URL}`);
		return LOCAL_BACKEND_URL;
	}

	return null;
}

async function fetchResources(backendUrl) {
	log('Fetching resources from API...');
	const resourcesUrl = `${backendUrl}/api/v1/authz/resources`;

	const { data: response } = await axios.get(resourcesUrl);

	return response;
}

function transformResponse(apiResponse) {
	if (!apiResponse.data) {
		throw new Error('Invalid API response: missing data field');
	}

	const { resources, relations } = apiResponse.data;

	return {
		status: apiResponse.status || 'success',
		data: {
			resources: resources,
			relations: relations,
		},
	};
}

function generateTypeScriptFile(data) {
	const resourcesStr = data.data.resources
		.map(
			(r) =>
				`\t\t\t{\n\t\t\t\tname: '${r.name}',\n\t\t\t\ttype: '${r.type}',\n\t\t\t},`,
		)
		.join('\n');

	const relationsStr = Object.entries(data.data.relations)
		.map(
			([type, relations]) =>
				`\t\t\t${type}: [${relations.map((r) => `'${r}'`).join(', ')}],`,
		)
		.join('\n');

	return `// AUTO GENERATED FILE - DO NOT EDIT - GENERATED BY scripts/generate-permissions-type
export default {
\tstatus: '${data.status}',
\tdata: {
\t\tresources: [
${resourcesStr}
\t\t],
\t\trelations: {
${relationsStr}
\t\t},
\t},
} as const;
`;
}

async function main() {
	try {
		log('Starting permissions type generation...');

		const backendUrl = await discoverBackendUrl();

		if (!backendUrl) {
			console.error('\n' + '='.repeat(80));
			console.error('ERROR: No running SigNoz backend found!');
			console.error('='.repeat(80));
			console.error(
				'\nThe permissions type generator requires a running SigNoz backend.',
			);
			console.error('\nFor local development, start the backend with:');
			console.error('  make go-run-enterprise');
			console.error(
				'\nFor CI or integration testing, start the test environment with:',
			);
			console.error('  make py-test-setup');
			console.error(
				'\nIf running in CI and seeing this error, check that the py-test-setup',
			);
			console.error('step completed successfully before this step runs.');
			console.error('='.repeat(80) + '\n');
			process.exit(1);
		}

		log('Fetching resources...');
		const apiResponse = await fetchResources(backendUrl);

		log('Transforming response...');
		const transformed = transformResponse(apiResponse);

		log('Generating TypeScript file...');
		const content = generateTypeScriptFile(transformed);

		log(`Writing to ${PERMISSIONS_TYPE_FILE}...`);
		fs.writeFileSync(PERMISSIONS_TYPE_FILE, content, 'utf8');

		const rootDir = path.join(__dirname, '../..');
		const relativePath = path.relative(
			path.join(rootDir, 'frontend'),
			PERMISSIONS_TYPE_FILE,
		);
		log('Linting generated file...');
		execSync(`cd frontend && yarn oxlint ${relativePath}`, {
			cwd: rootDir,
			stdio: 'inherit',
		});

		log('Successfully generated permissions.type.ts');
	} catch (error) {
		log(`Error: ${error.message}`);
		process.exit(1);
	}
}

if (require.main === module) {
	main();
}

module.exports = { main };
