import { parseDocument, stringify, Document } from 'yaml';
import { readYaml, readMultiYaml, convertToYAMLString, convertParsedYmlToString, parseYamlContent } from './yaml-helper';
import yaml from 'js-yaml';

jest.mock('js-yaml');
jest.mock('yaml');

describe('YAML-Helper test suite', () => {
    const mockYamlObject = { key: 'value' };
    const mockYamlArray = [{ key: 'value1' }, { key: 'value2' }];
    const mockYamlString = 'key: value';
    const mockYamlMultiString = `
key1: value1
---
key2: value2
`;
    const mockFileName = 'test.yaml';

    // Define a mock that satisfies Document<Node, true>
    const mockYamlDocument = {
        commentBefore: '',
        comment: '',
        contents: [],
        directives: [],
        errors: [],
        options: {},
        schema: {},
        warnings: [],
        toString: jest.fn(() => 'key: value'),
    } as unknown as Document; // Cast to Document type

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

    describe('readYaml', () => {
        it('should read and parse a YAML string into an object', () => {
            (yaml.load as jest.Mock).mockReturnValue(mockYamlObject);

            const result = readYaml<typeof mockYamlObject>(mockYamlString);

            expect(yaml.load).toHaveBeenCalledWith(mockYamlString);
            expect(result).toEqual(mockYamlObject);
        });

        it('should throw an error if the YAML input is invalid', () => {
            (yaml.load as jest.Mock).mockImplementation(() => {
                throw new Error('Invalid YAML');
            });

            expect(() => readYaml<typeof mockYamlObject>('invalid yaml')).toThrow('Invalid YAML');
        });
    });

    describe('readMultiYaml', () => {
        it('should read and parse a multi-document YAML string into an array of objects', () => {
            (yaml.loadAll as jest.Mock).mockReturnValue(mockYamlArray);

            const result = readMultiYaml<typeof mockYamlObject>(mockFileName, mockYamlMultiString);

            expect(yaml.loadAll).toHaveBeenCalledWith(mockYamlMultiString);
            expect(result).toEqual(mockYamlArray);
        });

        it('should throw an error if the multi-document YAML input is invalid', () => {
            (yaml.loadAll as jest.Mock).mockImplementation(() => {
                throw new Error('Invalid YAML');
            });

            expect(() => readMultiYaml<typeof mockYamlObject>(mockFileName, 'invalid yaml')).toThrowError(
                new Error('Error processing YAML file test.yaml: Invalid Yaml')
            );
        });
    });

    describe('convertToYAMLString', () => {
        it('should convert an object to a YAML string', () => {
            (yaml.dump as jest.Mock).mockReturnValue(mockYamlString);

            const result = convertToYAMLString(mockYamlObject);

            expect(yaml.dump).toHaveBeenCalledWith(mockYamlObject);
            expect(result).toEqual(mockYamlString);
        });
    });

    describe('parseYamlContent', () => {
        it('should parse valid YAML content into a Document', () => {
            (parseDocument as jest.Mock).mockReturnValue(mockYamlDocument);

            const result = parseYamlContent(mockYamlString);

            expect(parseDocument).toHaveBeenCalledWith(mockYamlString);
            expect(result).toEqual(mockYamlDocument);
        });

        it('should throw an error if the YAML content is invalid', () => {
            (parseDocument as jest.Mock).mockImplementation(() => {
                throw new Error('Failed to parse YAML');
            });

            expect(() => parseYamlContent('invalid yaml')).toThrow('Failed to parse YAML content.');
        });
    });

    describe('convertParsedYmlToString', () => {
        it('should convert a Document to a YAML string', () => {
            (stringify as jest.Mock).mockReturnValue(mockYamlString);

            const result = convertParsedYmlToString(mockYamlDocument);

            expect(stringify).toHaveBeenCalledWith(mockYamlDocument);
            expect(result).toEqual(mockYamlString);
        });

        it('should throw an error if the conversion fails', () => {
            (stringify as jest.Mock).mockImplementation(() => {
                throw new Error('Failed to convert');
            });

            expect(() => convertParsedYmlToString(mockYamlDocument)).toThrow('Failed to convert YAML document to string.');
        });
    });
});
