import path from 'path';
import fs from 'fs';
import {ProjectAssetValidator} from '../src/validator/asset-validator.js';
import {BuildProjectAssets} from '../src/build-project-assets.js';
import JSZip from 'jszip';
import {normalizeZipPaths, ReferenceValidationResultMap, resolveRelativePaths} from '../src/index.js';

jest.mock('../src/service/log-wrapper.ts');

jest.mock('@apic/studio-shared', () => ({
	ErrorResponse: jest.fn(),
	Metadata_Ref: jest.fn(),
	SpecObject: jest.fn(),
	YamlContent: jest.fn(),
	UpperCaseKinds: jest.fn(),
}));
describe('Build Asset Project Modules', () => {
	
	let validationResult: ReferenceValidationResultMap;
	
	it('should process the zip and return zip content ', async () => {
		const zipFilePath = path.resolve(__dirname, './assets/gateway-asset.zip');
		const Buffer = fs.readFileSync(zipFilePath);
		const obj = new BuildProjectAssets();
		const result = await obj['loadZipFromBuffer'](Buffer);
		expect(result).not.toBe(null);
		expect(result).not.toBe(undefined);
		expect(result).not.toBe(false);

	});

	it('should validate the zip and return true ', async () => {
		const zipFilePath = path.resolve(__dirname, './assets/gateway-multi-project-asset.zip');
		const Buffer = fs.readFileSync(zipFilePath);
		const zip2 = await JSZip.loadAsync(Buffer);
		const normalizedBuffer=await normalizeZipPaths(zip2);
		const zip3= await resolveRelativePaths(await normalizedBuffer.generateAsync({ type: 'nodebuffer' }));
		const buffer2=await zip3.generateAsync({ type: 'nodebuffer' });
		const obj = new BuildProjectAssets();
		const result = await obj['validate'](buffer2);
		validationResult = result;
		expect(result).not.toBe(null);
		expect(result).not.toBe(undefined);
		expect(result.isValid).not.toBe(false);
		expect(result.isValid).toBe(true);
		expect(result.allRefMaps).not.toBe(null);
		expect(result.allRefMaps).not.toBe(undefined);
		
		const allRefMaps = result.allRefMaps;
		expect(allRefMaps.size).toBeGreaterThan(0);
		allRefMaps.forEach((refMap, folderName) => {
			expect(refMap).toBeInstanceOf(Map);
			expect(folderName).toBeDefined();
			expect(folderName).not.toBe('');
		});

	});

	it('should extract foldername and filepaths in folder ', async () => {
		const zipFilePath = path.resolve(__dirname, './assets/gateway-multi-project-asset.zip');
		const Buffer = fs.readFileSync(zipFilePath);
		const obj = new BuildProjectAssets();
		const folderNames = new Set<string>();
		const filePathsInFolder = new Set<string>();
		await obj['extractFolderNamesAndPaths'](Buffer,folderNames,filePathsInFolder);
		expect(folderNames.size).not.toBeLessThan(1);
		expect(filePathsInFolder.size).not.toBeLessThan(1);
        
	});

	it('should run all the asset validator function and return true ', async () => {
		const zipFilePath = path.resolve(__dirname, './assets/gateway-multi-project-asset.zip');
		const Buffer = fs.readFileSync(zipFilePath);
		const zip2 = await JSZip.loadAsync(Buffer);
		const normalizedBuffer=await normalizeZipPaths(zip2);
		const zip3= await resolveRelativePaths(await normalizedBuffer.generateAsync({ type: 'nodebuffer' }));
		const buffer2=await zip3.generateAsync({ type: 'nodebuffer' });
		const obj = new BuildProjectAssets();
		const folderNames = new Set<string>();
		const filePathsInFolder = new Set<string>();
		await obj['extractFolderNamesAndPaths'](buffer2,folderNames,filePathsInFolder);
		const asset = new ProjectAssetValidator();
		const result = await obj['validateFolder'](buffer2,'project1',asset,filePathsInFolder, folderNames);
		expect(result.isValid).toBe(true);


	});

	it('should get the file if it is present in the zip else return null ', async () => {
		const zipFilePath = path.resolve(__dirname, './assets/gateway-multi-project-asset.zip');
		const Buffer = fs.readFileSync(zipFilePath);
		const obj = new BuildProjectAssets();
		const result = await obj['getFileFromZip'](Buffer,'project2/petstore.yaml');
		expect(result).not.toBe(null);
		const result2 = await obj['getFileFromZip'](Buffer,'project22/petstore.yaml');
		expect(result2).toBe(null);
	});

	it('should create the zip that is passed to gateway  ', async () => {
		const zipFilePath = path.resolve(__dirname, './assets/gateway-multi-project-asset.zip');
		const Buffer = fs.readFileSync(zipFilePath);
		const obj = new BuildProjectAssets();
		const result = await obj['createProjectBuildZip'](Buffer, validationResult.allRefMaps);
		expect(result).not.toBe(null);
		expect(result).not.toBe(undefined);
		expect(result).not.toBe(false);

	});

	it('should create a consolidated yaml and add to the zip that is build ', async () => {
		const zipFilePath = path.resolve(__dirname, './assets/gateway-multi-project-asset.zip');
		const Buffer = fs.readFileSync(zipFilePath);
		const obj = new BuildProjectAssets();
		const folderNames = new Set<string>();
		const filePathsInFolder = new Set<string>();
		await obj['extractFolderNamesAndPaths'](Buffer,folderNames,filePathsInFolder);
		const zip = new JSZip();
		await obj['addConsolidatedYAMLs'](zip,Buffer,folderNames, validationResult.allRefMaps);
		const files = Object.keys(zip.files);
		expect(files.length).toBeGreaterThan(0);
	});

	it('should add the non asset file to the resource folder  ', async () => {
		const zipFilePath = path.resolve(__dirname, './assets/gateway-multi-project-asset.zip');
		const Buffer = fs.readFileSync(zipFilePath);
		const obj = new BuildProjectAssets();
		const zip2 = await JSZip.loadAsync(Buffer);
		const normalizedBuffer=await normalizeZipPaths(zip2);
		const zip3= await resolveRelativePaths(await normalizedBuffer.generateAsync({ type: 'nodebuffer' }));
		const folderNames = new Set<string>();
		const filePathsInFolder = new Set<string>();
		const buffer2=await zip3.generateAsync({ type: 'nodebuffer' });
		await obj['extractFolderNamesAndPaths'](buffer2,folderNames,filePathsInFolder);
		const zip = new JSZip();
		await obj['addReferencedFiles'](zip,buffer2,folderNames);

		const files = Object.keys(zip.files);
		expect(files.length).toBeGreaterThan(0);
	});
	it('should create consolidated yaml for specific project ', async () => {
		const zipFilePath = path.resolve(__dirname, './assets/gateway-multi-project-asset.zip');
		const Buffer = fs.readFileSync(zipFilePath);
		const obj = new BuildProjectAssets();
		const zip2 = await JSZip.loadAsync(Buffer);
		const normalizedBuffer=await normalizeZipPaths(zip2);
		const buffer2=await normalizedBuffer.generateAsync({ type: 'nodebuffer' });
		let result ='';
		result = await obj['createConsolidatedYaml'](buffer2,'project1', validationResult.allRefMaps);
		expect(result).not.toBe('');
		expect(result.length).toBeGreaterThan(0);

	});

	it('should process the project zip and return the build zip ', async () => {
		const zipFilePath = path.resolve(__dirname, './assets/gateway-multi-project-asset.zip');
		const Buffer = fs.readFileSync(zipFilePath);
		const obj = new BuildProjectAssets();
		const zip2 = await JSZip.loadAsync(Buffer);
		const normalizedBuffer=await normalizeZipPaths(zip2);
		const zip3= await resolveRelativePaths(await normalizedBuffer.generateAsync({ type: 'nodebuffer' }));
		const buffer2=await zip3.generateAsync({ type: 'nodebuffer' });
		const result=await obj.processProjectZip(buffer2);
		expect(result).not.toBe(undefined);
		expect(result?.files['project1.yaml'].name).toBe('project1.yaml');

	});

	it('should process the project zip and return Gateway json ', async () => {
		const zipFilePath = path.resolve(__dirname, './assets/gateway-multi-project-asset.zip');
		const Buffer = fs.readFileSync(zipFilePath);
		const obj = new BuildProjectAssets();
		const result=await obj.extractGatewaysJson(Buffer);
		expect(result).not.toBe(undefined);
		expect(result).not.toBe(null);
		expect(result.gateways.length).toBeGreaterThan(0);
	});

	it('should create consolidated yaml for dependencies within project ', async () => {
		const zipFilePath = path.resolve(__dirname, './assets/gateway-projects-dependent-asset.zip');
		const Buffer = fs.readFileSync(zipFilePath);
		const obj = new BuildProjectAssets();
		const zip2 = await JSZip.loadAsync(Buffer);
		const normalizedBuffer=await normalizeZipPaths(zip2);
		const buffer2=await normalizedBuffer.generateAsync({ type: 'nodebuffer' });
		let result ='';
		const allRefMaps = new Map<string, Map<string, boolean>>([
			['project1', new Map([['dev:SwaggerrAPI:1.0', true], ['dev:dev_policies:1.0', true], ['dev:default_endpoint:1.0', true]])],
			['project2', new Map([['dev:dev_policies:1.0', true]])]
		]);
		result = await obj['createConsolidatedYaml'](buffer2,'project1', allRefMaps);
		expect(result).not.toBe('');
		expect(result.length).toBeGreaterThan(0);

	});

});
