/**
* Copyright Super iPaaS Integration LLC, an IBM Company 2024
*/
/* eslint-disable @typescript-eslint/no-explicit-any */
import AdmZip from 'adm-zip';
import { loadCacheWithProject } from './asset-cache-helper.js';
import { isYamlFile } from '../common/fs-helper.js';
import { readMultiYaml } from '../common/yaml-helper.js';
import { isValidAsset } from './asset-helper.js';
import { AssetCache } from '../../cache/asset-cache.js';
import { getRefsFromAsset } from '../../handlers/asset-handler.js';
import { BaseAsset } from '../../model/assets-model.js';


jest.mock('../common/fs-helper.js', () => ({
	isYamlFile: jest.fn(),
}));

jest.mock('../common/yaml-helper.js', () => ({
	readMultiYaml: jest.fn(),
}));

jest.mock('./asset-helper.js', () => ({
	isValidAsset: jest.fn(),
}));

jest.mock('../common/message-helper.js', () => ({
	showWarning: jest.fn(),
	showInfo: jest.fn()
}));

jest.mock('../../cache/asset-cache.js', () => {
	return {
		AssetCache: {
			getInstance: jest.fn().mockReturnValue({
				markAsProcessed: jest.fn(),
				checkAndMarkAsUnProcessed: jest.fn(),
			}),
		},
	};
});

jest.mock('../../handlers/asset-handler.js', () => ({
	getRefsFromAsset: jest.fn(),
}));
describe('Asset cache helper function test suite', () => {
    
	afterEach(() => {
		jest.clearAllMocks();
	});
	it('should handle empty zip', () => {
		const zip = new AdmZip();
		jest.spyOn(zip, 'getEntries').mockReturnValue([]);
    
		loadCacheWithProject(zip);
    
		expect(readMultiYaml).not.toHaveBeenCalled();
		expect(isValidAsset).not.toHaveBeenCalled();
		expect(AssetCache.getInstance().markAsProcessed).not.toHaveBeenCalled();
		expect(getRefsFromAsset).not.toHaveBeenCalled();
	});
	it('should handle zip with invalid asset', () => {
		const zip = new AdmZip();
		const mockAsset = { kind: 'invalidKind', metadata: { name: 'invalidName' } } as BaseAsset;
		jest.spyOn(zip, 'getEntries').mockReturnValue([
          { entryName: 'asset.yml', isDirectory: false, getData: jest.fn().mockReturnValue(Buffer.from('invalid yaml')) } as any,
		]);
    
		(isYamlFile as jest.Mock).mockReturnValue(true);
		(readMultiYaml as jest.Mock).mockReturnValue([mockAsset]);
		(isValidAsset as jest.Mock).mockReturnValue(false);
    
		loadCacheWithProject(zip);
    
		expect(readMultiYaml).toHaveBeenCalledWith('asset.yml', 'invalid yaml');
		expect(isValidAsset).toHaveBeenCalledWith(mockAsset);
		expect(AssetCache.getInstance().markAsProcessed).not.toHaveBeenCalled();
		expect(getRefsFromAsset).not.toHaveBeenCalled();
	});
	it('should handle zip with non-yaml files', () => {
		const zip = new AdmZip();
		jest.spyOn(zip, 'getEntries').mockReturnValue([
          { entryName: 'file.txt', isDirectory: false, getData: jest.fn() } as any,
          { entryName: 'image.png', isDirectory: false, getData: jest.fn() } as any,
		]);
    
		(isYamlFile as jest.Mock).mockReturnValue(false);
    
		loadCacheWithProject(zip);
    
		expect(readMultiYaml).not.toHaveBeenCalled();
		expect(isValidAsset).not.toHaveBeenCalled();
		expect(AssetCache.getInstance().markAsProcessed).not.toHaveBeenCalled();
		expect(getRefsFromAsset).not.toHaveBeenCalled();
	});
    
	it('should handle zip with one valid asset', () => {
		const zip = new AdmZip();
		const mockAsset = { kind: 'validKind', metadata: { name: 'validName' } } as BaseAsset;
		const mockRefs = [{ kind: 'refKind', metadata: { name: 'refName' } }] as BaseAsset[];
    
		jest.spyOn(zip, 'getEntries').mockReturnValue([
          { entryName: 'asset.yml', isDirectory: false, getData: jest.fn().mockReturnValue(Buffer.from('valid yaml')) } as any,
		]);
    
		(isYamlFile as jest.Mock).mockReturnValue(true);
		(readMultiYaml as jest.Mock).mockReturnValue([mockAsset]);
		(isValidAsset as jest.Mock).mockReturnValue(true);
		(getRefsFromAsset as jest.Mock).mockReturnValue(mockRefs);
    
		loadCacheWithProject(zip);
    
		expect(readMultiYaml).toHaveBeenCalledWith('asset.yml', 'valid yaml');
		expect(isValidAsset).toHaveBeenCalledWith(mockAsset);
		expect(AssetCache.getInstance().markAsProcessed).toHaveBeenCalledWith(mockAsset);
		expect(getRefsFromAsset).toHaveBeenCalledWith(mockAsset);
		expect(AssetCache.getInstance().checkAndMarkAsUnProcessed).toHaveBeenCalledWith(mockRefs[0]);
	});
    
	
	it('should handle dependency assets correctly', () => {
		const zip = new AdmZip();
		const mockAsset = { kind: 'validKind', metadata: { name: 'validName' } } as BaseAsset;
		const mockRefAsset = { kind: 'refKind', metadata: { name: 'refName' } } as BaseAsset;
		const mockRefs = [mockRefAsset];
    
		jest.spyOn(zip, 'getEntries').mockReturnValue([
          { entryName: 'asset.yml', isDirectory: false, getData: jest.fn().mockReturnValue(Buffer.from('valid yaml')) } as any,
		]);
    
		(isYamlFile as jest.Mock).mockReturnValue(true);
		(readMultiYaml as jest.Mock).mockReturnValue([mockAsset]);
		(isValidAsset as jest.Mock).mockReturnValue(true);
		(getRefsFromAsset as jest.Mock).mockReturnValue(mockRefs);
    
		loadCacheWithProject(zip);
    
		expect(readMultiYaml).toHaveBeenCalledWith('asset.yml', 'valid yaml');
		expect(isValidAsset).toHaveBeenCalledWith(mockAsset);
		expect(AssetCache.getInstance().markAsProcessed).toHaveBeenCalledWith(mockAsset);
		expect(getRefsFromAsset).toHaveBeenCalledWith(mockAsset);
		expect(AssetCache.getInstance().checkAndMarkAsUnProcessed).toHaveBeenCalledWith(mockRefAsset);
	});
    
	it('should process multiple valid assets in one YAML file', () => {
		const zip = new AdmZip();
		const mockAssets = [
          { kind: 'validKind1', metadata: { name: 'validName1' } } as BaseAsset,
          { kind: 'validKind2', metadata: { name: 'validName2' } } as BaseAsset,
		];
    
		jest.spyOn(zip, 'getEntries').mockReturnValue([
          { entryName: 'assets.yml', isDirectory: false, getData: jest.fn().mockReturnValue(Buffer.from('multiple valid yaml')) } as any,
		]);
    
		(isYamlFile as jest.Mock).mockReturnValue(true);
		(readMultiYaml as jest.Mock).mockReturnValue(mockAssets);
		(isValidAsset as jest.Mock).mockReturnValue(true);
    
		loadCacheWithProject(zip);
    
		mockAssets.forEach(asset => {
			expect(isValidAsset).toHaveBeenCalledWith(asset);
			expect(AssetCache.getInstance().markAsProcessed).toHaveBeenCalledWith(asset);
		});
		expect(readMultiYaml).toHaveBeenCalledWith('assets.yml','multiple valid yaml');
	});
    
	it('should process valid assets and skip invalid ones in one YAML file', () => {
		const zip = new AdmZip();
		const validAsset = { kind: 'validKind', metadata: { name: 'validName' } } as BaseAsset;
		const invalidAsset = { kind: 'invalidKind', metadata: { name: 'invalidName' } } as BaseAsset;
    
		jest.spyOn(zip, 'getEntries').mockReturnValue([
          { entryName: 'assets.yml', isDirectory: false, getData: jest.fn().mockReturnValue(Buffer.from('valid and invalid yaml')) } as any,
		]);
    
		(isYamlFile as jest.Mock).mockReturnValue(true);
		(readMultiYaml as jest.Mock).mockReturnValue([validAsset, invalidAsset]);
		(isValidAsset as jest.Mock)
			.mockReturnValueOnce(true) // validAsset
			.mockReturnValueOnce(false); // invalidAsset
    
		loadCacheWithProject(zip);
    
		expect(readMultiYaml).toHaveBeenCalledWith('assets.yml', 'valid and invalid yaml');
		expect(isValidAsset).toHaveBeenCalledWith(validAsset);
		expect(isValidAsset).toHaveBeenCalledWith(invalidAsset);
		expect(AssetCache.getInstance().markAsProcessed).toHaveBeenCalledWith(validAsset);
		expect(AssetCache.getInstance().markAsProcessed).not.toHaveBeenCalledWith(invalidAsset);
	});

});