const fs = require('node:fs');
const path = require('node:path');
const schema = require('./data/eds-c-form.schema.json');
const dataAttributesSchema = require('../eds-c-data-attributes/data/eds-c-data-attributes.schema.json');
const labelSchema = require('../eds-c-label/data/eds-c-label.schema.json');
const hintSchema = require('../eds-c-hint/data/eds-c-hint.schema.json');
const errorMessageSchema = require('../eds-c-error-message/data/eds-c-error-message.schema.json');
const errorSummarySchema = require('../eds-c-error-summary/data/eds-c-error-summary.schema.json');
const inputSchema = require('../eds-c-input/data/eds-c-input.schema.json');
const buttonSchema = require('../eds-c-button/data/eds-c-button.schema.json');
const exampleJson = require('./data/eds-c-form.example.json');
const handlebars = require('handlebars');

const {findTemplates} = require('../../development/tests/templateLoader.js');
const { validateSchema } = require('../../development/tests/validate-schema');
findTemplates(['eds-c-form', 'eds-c-input', 'eds-c-error-summary', 'eds-c-label', 'eds-c-error-message', 'eds-c-button', 'eds-c-data-attributes']).load(handlebars);

const componentTemplate = '{{> eds-c-form}}';
const componentHbs = handlebars.compile(componentTemplate);
const renderedComponent = componentHbs(exampleJson);

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

describe('Form 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 valid = validateSchema(schema, exampleJson, [
            { name: 'eds-c-error-summary', schema: errorSummarySchema },
            { name: 'eds-c-input', schema: inputSchema },
            { name: 'eds-c-button', schema: buttonSchema },
            { name: 'eds-c-label', schema: labelSchema },
            { name: 'eds-c-hint', schema: hintSchema },
            { name: 'eds-c-error-message', schema: errorMessageSchema },
            { name: 'eds-c-data-attributes', schema: dataAttributesSchema }
        ]);
        expect(valid).toBeTruthy();
    });

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

        const formElement = document.querySelector('.eds-c-form');
        expect(formElement).not.toBeNull();
        expect(formElement.getAttribute('method')).toEqual('POST');
    });

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

        const formElement = document.querySelector('.eds-c-form');
        expect(formElement.getAttribute('data-test')).toEqual('test-form');
        expect(formElement.getAttribute('data-track-context')).toEqual('springer-link');
    });

    test('Error summary is displayed', () => {
        document.body.innerHTML = renderedComponent;

        const errorSummaryElement = document.querySelector('.eds-c-error-summary');
        expect(errorSummaryElement).not.toBeNull();
    });

    test('Form heading is displayed', () => {
        const { formHeading } = exampleJson;
        document.body.innerHTML = renderedComponent;

        const formHeadingElement = document.querySelector(`.eds-c-form ${formHeading.formHeadingTag}`);
        expect(formHeadingElement).not.toBeNull();
        expect(formHeadingElement.getAttribute('id')).toEqual('form-one');
        expect(formHeadingElement.textContent.replace(/\s+/g, ' ').trim()).toBe('This is the label of the form');
    });
    
    test('Buttons render stacked when uiSettings.buttonsSettings.stack is true', () => {
        // use the example json which has stack: true and stackFullWidth: true
        document.body.innerHTML = renderedComponent;

        // outer container should be l-stack when stacked
        const outer = document.querySelector('[data-test="eds-c-form-buttons-container"]');
        expect(outer).not.toBeNull();
        expect(outer.classList.contains('l-stack')).toBeTruthy();

        const stackInner = document.querySelector('.eds-c-form__buttons-stack');
        expect(stackInner).not.toBeNull();
        // stackFullWidth true on example should add modifier class
        expect(stackInner.classList.contains('eds-c-form__buttons-stack--full-width')).toBeTruthy();
    });

    test('Buttons container has l-cluster and custom cssClass when not stacked', () => {
        // clone example and set stack to false, and supply a cssClass to assert it is applied
        const modified = JSON.parse(JSON.stringify(exampleJson));
        modified.uiSettings = modified.uiSettings || {};
        modified.uiSettings.buttonsSettings = modified.uiSettings.buttonsSettings || {};
        modified.uiSettings.buttonsSettings.stack = false;

        const componentHbs = handlebars.compile(componentTemplate);
        const renderedWithModifiedData = componentHbs(modified);
        document.body.innerHTML = renderedWithModifiedData;

        const cluster = document.querySelector('[data-test="eds-c-form-buttons-container"]');
        expect(cluster).not.toBeNull();
        expect(cluster.classList.contains('l-cluster')).toBeTruthy();
    });
    
    test('Template passes basic HTML accessibility', async () => {
        expect(await axe(renderedComponent)).toHaveNoViolations();
    });
});