const schema = require('./data/eds-c-accordion.schema.json');
const exampleJson = require('./data/eds-c-accordion.example.json');
const fs = require('node:fs');
const path = require('node:path');
const componentTemplate = '{{> eds-c-accordion }}';
const Ajv = require('ajv');
const ajv = new Ajv();
const handlebars = require('handlebars');

const {findTemplates} = require('../../development/tests/templateLoader.js');
findTemplates(['eds-c-accordion']).load(handlebars);

const componentHbs = handlebars.compile(componentTemplate);
const renderedComponent = componentHbs(exampleJson);

describe('EDS accordion message component', () => {
    test('docs file exists', () => {
        const exists = fs.existsSync(path.resolve(__dirname, 'docs.md'));
        expect(exists).toBe(true);
    });
});

const validateData = (data) => {
    const requiredFields = ['id', 'title', 'content'];
    requiredFields.forEach(field => {
    if (!data[field]) {
        throw new Error(`${field} is required`);
    }
    });
};

describe(' EDS accordion schema validation and accessibility test', () => {

    const { configureAxe, toHaveNoViolations } = require('jest-axe');
    expect.extend(toHaveNoViolations);
    
    const axe = configureAxe({
        rules: {
            region: { enabled: false }
        }
    });
    
    test('Example data matches schema', () => {
        const validate = ajv.compile(schema);
        const valid = validate(exampleJson);
    
        if (!valid) {
            // Extract and format the Ajv validation errors
            const errors = validate.errors.map((error) => ajv.errorsText([error])).join('\n');
            throw new Error(errors);
        }
    
        expect(valid).toBeTruthy();
    });

    test('Template passes basic HTML accessibility', async () => {
        expect(await axe(renderedComponent)).toHaveNoViolations();
    });
});

describe('Accordion Template', () => {

    test('renders correctly when all fields are present', () => {
        validateData(exampleJson);
        const result = componentHbs(exampleJson);

        expect(result).toContain('id="test1"');
        expect(result).toContain('For authors');
        expect(result).toContain('data-eds-c-accordion');
    });

    test('Button element aria-expanded should be true when open is true', () => {
        const testData = { ...exampleJson, open: true };
        document.body.innerHTML = componentHbs(testData);
        const buttonElement = document.querySelector('.eds-c-accordion__button');
        expect(buttonElement.getAttribute('aria-expanded')).toBe('true');
    });

    test('Button data attributes are correct', () => {
        document.body.innerHTML = renderedComponent;

        const buttonElement = document.querySelector('.eds-c-accordion__button');
        expect(buttonElement.getAttribute('data-test')).toEqual('accordion-test');
        expect(buttonElement.getAttribute('data-track')).toEqual('some-event-name');
    });

    test('Header element aria-level should be set when headingLevel is set', () => {
        const testData = { ...exampleJson };
        document.body.innerHTML = componentHbs(testData);
        const headerElement = document.querySelector('.eds-c-accordion__header');
        expect(headerElement.getAttribute('aria-level')).toBe('3');
    });

    test('Title element should be present', () => {
        document.body.innerHTML = renderedComponent;
        const titleElement = document.querySelector('.eds-c-accordion__title');
        expect(titleElement.textContent.trim()).toBe('For authors');
    });

    test('Icon element should be present', () => {
        document.body.innerHTML = renderedComponent;
        const icon = document.querySelector('.eds-c-accordion__icon');
        const xlinkHref = icon.querySelector('use').getAttribute('xlink:href');
        expect(icon).not.toBeNull();
        expect(xlinkHref).toBe('../img/eds-i-chevron-down-small.svg#eds-i-chevron-down-small');
    });

    test('Ids should be set correctly', () => {
        const {id} = exampleJson;
        document.body.innerHTML = renderedComponent;
        const buttonElement = document.getElementById(id);
        const contentElement = document.getElementById(`eds-c-accordion-content-${id}`);
        expect(buttonElement.getAttribute('aria-controls')).toBe('eds-c-accordion-content-test1');
        expect(contentElement.getAttribute('aria-labelledby')).toBe('test1');
    });

    test('content element aria-expanded should have correct CSS class when groupedContent is true', () => {
        const testData = { ...exampleJson, groupedContent: true };
        const {id} = exampleJson;
        document.body.innerHTML = componentHbs(testData);
        const contentElement = document.getElementById(`eds-c-accordion-content-${id}`);
        expect(contentElement.classList.contains('eds-c-accordion__content--grouped')).toBe(true);
    });

    test('throws error if id is missing', () => {
        const { id, ...newData } = exampleJson;
        expect(() => validateData(newData)).toThrow('id is required');
    });

    test('throws error if title is missing', () => {
        const { title, ...newData } = exampleJson;
        expect(() => validateData(newData)).toThrow('title is required');
    });

    test('throws error if content is missing', () => {
        const { content, ...newData } = exampleJson;
        expect(() => validateData(newData)).toThrow('content is required');
    });
});