/**
* Copyright Super iPaaS Integration LLC, an IBM Company 2024
*/
import JSZip from 'jszip';
import yaml from 'js-yaml';
import { TypeConvertor } from '../converter/type.converter.js';
import { YamlContent, SpecObject, AssetManagerInterface, TestMetadata } from '../models/interface.js';
import { LogWrapper } from '../service/log-wrapper.js';

export class AssetParser implements AssetManagerInterface {
	private readonly obj = new TypeConvertor();

	async createAssetReferenceMap(buffer: Buffer): Promise<Map<string, boolean>> {
		const zip = new JSZip();
		const refMap = new Map<string, boolean>();

		const zipContent = await zip.loadAsync(buffer);

		for (const [fileName, file] of Object.entries(zipContent.files)) {
			if (fileName.endsWith('.yaml') || fileName.endsWith('.yml')) {
				const content = await file.async('string');
				try {
					const yamlContents = yaml.loadAll(content) as YamlContent[];
					for (const yamlContent of yamlContents) {
						if(yamlContent.kind.toLowerCase()==='test') {
							this.extractRefs(yamlContent, refMap);
						}
						this.updateMapWithMetadata(yamlContent, refMap);
						
					}
				} catch (err) {
					LogWrapper.logError('0013', `parsing YAML in file ${fileName}`, (err as Error).message);
				}
			}
		}

		return refMap;
	}

	updateMapWithMetadata(yamlContent: YamlContent, refMap: Map<string, boolean>): void {
		const metadata = yamlContent.metadata as TestMetadata;
		const keyParts = [];

		if (metadata.namespace) {
			keyParts.push(metadata.namespace);
		}
		if (metadata.name) {
			keyParts.push(metadata.name);
		}

		const version = this.obj.toString(metadata.version);

		keyParts.push(version);
		const key = keyParts.join(':');
		refMap.set(key, true);
		LogWrapper.logDebug('0003', `Metadata key added to refMap: ${key}`);
	}

	async updateMapWithGatewayEndpoints(data: Buffer, refMap: Map<string, boolean>): Promise<void> {
		const zip = new JSZip();

		const zipContent = await zip.loadAsync(data);

		for (const [fileName, file] of Object.entries(zipContent.files)) {
			if (fileName.includes('api-gatewayEndpoints.json')) {
				const content = await file.async('string');
				const endpoints = JSON.parse(content);
				Object.keys(endpoints).forEach((key) => {
					refMap.set(key, true);
					LogWrapper.logInfo('0003', `Gateway endpoint added to refMap: ${key}`);
				});
			}
		}
	}

	private extractRefs(yamlContent: YamlContent, refMap: Map<string, boolean>): void {
		const extractRef = (obj: SpecObject) => {
			for (const key in obj) {
				const value = obj[key];
				if (key === '$ref' && typeof value === 'string') {
					const metadataWithUpdatedVersion=this.replaceVersionInString(value);
					if (!refMap.has(metadataWithUpdatedVersion)) {
						LogWrapper.logDebug('0003', `Reference found and added to refMap: ${value}`);
						refMap.set(metadataWithUpdatedVersion, false);
					}
				} else if (typeof value === 'object' && value !== null) {
					extractRef(value);
				}
			}
		};

		const specOb=JSON.stringify(yamlContent.spec);
		extractRef(yaml.load(specOb) as SpecObject);
	}

	private replaceVersionInString(input: string): string {
		const parts = input.split(':');
		const version=parts[parts.length-1];
		const numberPattern = /^-?\d+(\.\d+)?$/; // Matches integers and decimals
		if (numberPattern.test(version)) {
			 const numberVersion= parseFloat(version);
			 if(!isNaN(numberVersion)){
				parts[parts.length - 1]= this.obj.toString(numberVersion);
				return parts.join(':');
			 }
		}else{
			parts[parts.length - 1]= this.obj.toString(version);
			return	parts.join(':');
		}
		return input;
	}
}
