import AdmZip from 'adm-zip';
import path from 'path';
import { isYamlFile } from '../common/fs-helper.js';
import { convertParsedYmlToString, parseYamlContent } from '../common/yaml-helper.js';
import {
    FAILED_TO_PROCESS_ENTRY,
    NO_ENV_FILE
} from '../../constants/message-constants.js';
import { showError } from '../common/message-helper.js';
import { parseEnvInput, updateEnvironmentAssetInZip } from './env-helper.js';

jest.mock('adm-zip');
jest.mock('path');
jest.mock('../common/yaml-helper.js', () => {
    let initialVariables: { key: string; value: string }[] = [];
  
    const toJSMock = jest.fn(() => ({
        kind: 'Environment',
        spec: { variables: [...initialVariables] },
    }));
  
    const setInMock = jest.fn((path: string[], value: { key: string; value: string }) => {
        if (path.join('.') === 'spec.variables') {
            initialVariables = [...initialVariables, value];
            toJSMock.mockReturnValue({
                kind: 'Environment',
                spec: { variables: [...initialVariables] },
            });
        }
    });
  
    const hasInMock = jest.fn((path: string[]) => {
        return path.join('.') === 'spec.variables';
    });
  
    return {
        convertParsedYmlToString: jest.fn(),
        parseYamlContent: jest.fn((content: string) => ({
            toJS: toJSMock,
            setIn: setInMock,
            hasIn: hasInMock,
        })),
    };
  });
  





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

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

describe('Env helper test suite', () => {
    describe('parseEnvInput', () => {
        it('should correctly parse single key-value pairs', () => {
            const input = "key1=value1,key2=value2";
            const expected = {
                key1: 'value1',
                key2: 'value2',
            };
            expect(parseEnvInput(input)).toEqual(expected);
        });

        it('should correctly parse key with multiple comma-separated values', () => {
            const input = `key1="value1,value2",key2="value with spaces"`;
            const expected = {
                key1: 'value1,value2',
                key2: 'value with spaces',
            };
            expect(parseEnvInput(input)).toEqual(expected);
        });

        it('should handle spaces around keys and values', () => {
            const input = "  key1  = '  value1, value2  ' ,  key2  =  ' value with spaces '  ";
            const expected = {
                key1: 'value1, value2',
                key2: 'value with spaces',
            };
            expect(parseEnvInput(input)).toEqual(expected);
        });

        it('should throw an error for missing key', () => {
            const input = "=value";
            expect(() => parseEnvInput(input)).toThrow('Invalid environment variable format: Key must be provided for the value: =value');
        });

        it('should throw an error for missing value', () => {
            const input = "key1=";
            expect(() => parseEnvInput(input)).toThrow('Invalid environment variable format: Value must be provided for the key: key1');
        });

        it('should handle empty input gracefully', () => {
            const input = "";
            const expected = {};
            expect(parseEnvInput(input)).toEqual(expected);
        });

        it('should handle malformed input', () => {
            const input = "key1=value1,,key2=value2=";
            const expected = {
                key1: 'value1',
                key2: 'value2=',
            };
            expect(parseEnvInput(input)).toEqual(expected);
        });

        it('should handle quotes around keys and values', () => {
            const input = "'key1'='value1','key2'='value with spaces'";
            const expected = {
                key1: 'value1',
                key2: 'value with spaces',
            };
            expect(parseEnvInput(input)).toEqual(expected);
        });
    });

    describe('updateEnvironmentAssetInZip', () => {
        let mockZipBuffer: Buffer;
        let mockZip: AdmZip;
        let mockEntries: any[];

        beforeEach(() => {
            mockZipBuffer = Buffer.from('mock-zip-buffer');
            mockZip = {
                getEntries: jest.fn(),
                updateFile: jest.fn(),
                toBuffer: jest.fn(() => Buffer.from('updated-zip-buffer')),
            } as unknown as AdmZip;

            mockEntries = [
                { entryName: 'env/file1.yaml', getData: jest.fn(() => Buffer.from('yaml-content')) },
                { entryName: 'env/file2.yaml', getData: jest.fn(() => Buffer.from('yaml-content')) },
            ];

            (AdmZip as jest.Mock).mockImplementation(() => mockZip);
            mockZip.getEntries = jest.fn().mockReturnValue(mockEntries);
            (isYamlFile as jest.Mock).mockImplementation((path) => path.endsWith('.yaml'));

            jest.clearAllMocks();

            (convertParsedYmlToString as jest.Mock).mockReturnValue('updated-yaml-content');
            (path.normalize as jest.Mock).mockImplementation((p) => p);
        });

        afterEach(() => {
            jest.clearAllMocks();
        });

        it('should throw an error if no YAML files are found in the specified directory', async () => {
            mockZip.getEntries = jest.fn().mockReturnValue([]);
            await expect(updateEnvironmentAssetInZip(mockZipBuffer, { key: 'value' }, 'env'))
                .rejects.toThrow(`${NO_ENV_FILE} env`);
        });

        it('should update YAML files in the zip buffer', async () => {
          const envMap = { key: 'value' };
          await updateEnvironmentAssetInZip(mockZipBuffer, envMap, 'env');
          expect(convertParsedYmlToString).toHaveBeenCalled();
      });
      
      it('should update YAML files in the zip buffer with multiple key-value pairs', async () => {
        const envMap = { key1: 'value1', key2: 'value2' };
        await updateEnvironmentAssetInZip(mockZipBuffer, envMap, 'env');
        expect(convertParsedYmlToString).toHaveBeenCalled();
    });
    

        it('should handle errors while processing entries', async () => {
            mockEntries[0].getData.mockImplementation(() => {
                throw new Error('Failed to read file');
            });
            const envMap = { key: 'value' };
            await updateEnvironmentAssetInZip(mockZipBuffer, envMap, 'env');
            expect(showError).toHaveBeenCalledWith(`${FAILED_TO_PROCESS_ENTRY} env/file1.yaml: Failed to read file`);
        });
    });
});
