const fs = require('node:fs');
const path = require('node:path');
const schema = require('./data/eds-c-input.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 buttonSchema = require('../eds-c-button/data/eds-c-button.schema.json');
const exampleJson = require('./data/eds-c-input.example.json');
const handlebars = require('handlebars');

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

const componentTemplate = '{{> eds-c-input}}';

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

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

describe('Input 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-data-attributes', schema: dataAttributesSchema },
            { name: 'eds-c-label', schema: labelSchema },
            { name: 'eds-c-hint', schema: hintSchema },
            { name: 'eds-c-error-message', schema: errorMessageSchema },
            { name: 'eds-c-button', schema: buttonSchema }
        ]);
        expect(valid).toBeTruthy();
    });
    
    test('Should apply custom css classes', () => {
        document.body.innerHTML = renderedComponent;
        const container = document.querySelector('.eds-c-form__field');
        expect(container).not.toBeNull();
        expect(container.classList).toContain('custom-css-class');
        expect(container.hasAttribute('hidden')).toBeFalsy();
    });

    test('Should display a label', () => {
        document.body.innerHTML = renderedComponent;
        const container = document.querySelector('.eds-c-form__field');
        const labelElement = container.querySelector('.eds-c-label');
        expect(labelElement).not.toBeNull();
        expect(labelElement.textContent.replace(/\s+/g, ' ').trim()).toContain('Your name (optional)');
    });

    test('Should render hint', () => {
        document.body.innerHTML = renderedComponent;

        const hintElement = document.querySelector('.eds-c-hint');
        expect(hintElement).not.toBeNull();
        expect(hintElement.textContent.trim()).toBe('Your name is on your passport');
    });

    test('Should render error', () => {
        document.body.innerHTML = renderedComponent;

        const errorElement = document.querySelector('.eds-c-error-message');
        const inputElement = document.querySelector('.eds-c-form__input');
        expect(errorElement).not.toBeNull();
        expect(errorElement.textContent.trim()).toBe('Enter your name');
        expect(inputElement.hasAttribute('invalid')).toBeTruthy();
        expect(inputElement.getAttribute('aria-invalid')).toBeTruthy();
        expect(inputElement.getAttribute('aria-describedby')).toBe('error-eds-text-one');
    });

    test('Should render datalist', () => {
        const {datalist} = exampleJson;
        document.body.innerHTML = renderedComponent;

        const datalistElement = document.querySelector('.eds-c-form__field datalist');
        const optionElements = document.querySelectorAll('.eds-c-form__field datalist option');
        expect(datalistElement).not.toBeNull();
        expect(datalistElement.getAttribute('id')).toBe('my-datalist-id');
        expect([...optionElements].length).toBe(2);
        [...optionElements].forEach((optionElement, i) => {
            expect(optionElement.getAttribute('value')).toBe(datalist.options[i]);
        })
    });

    test('Should render mandatory attributes', () => {
        document.body.innerHTML = renderedComponent;

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement).not.toBeNull();
        expect(inputElement.getAttribute('id')).toBe('your-name-input-id');
        expect(inputElement.getAttribute('type')).toBe('text');
        expect(inputElement.getAttribute('name')).toBe('your-name');
    });

    test('Should render value attribute', () => {
        document.body.innerHTML = renderedComponent;

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.getAttribute('value')).toBe('Jane');
    });

    test('Should render require attribute', () => {
        const testData = { ...exampleJson, required: true };
        document.body.innerHTML = componentHbs(testData);

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.hasAttribute('required')).toBeTruthy();
        expect(inputElement.getAttribute('aria-required')).toBeTruthy();
    });

    test('Should render disabled attribute', () => {
        const testData = { ...exampleJson, disabled: true };
        document.body.innerHTML = componentHbs(testData);

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.hasAttribute('disabled')).toBeTruthy();
    });

    test('Should render readonly attribute', () => {
        const testData = { ...exampleJson, readonly: true };
        document.body.innerHTML = componentHbs(testData);

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.hasAttribute('readonly')).toBeTruthy();
    });

    test('Should render max attribute', () => {
        const testData = { ...exampleJson, max: 70 };
        document.body.innerHTML = componentHbs(testData);

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.getAttribute('max')).toBe('70');
    });


    test('Should render maxlength attribute', () => {
        const testData = { ...exampleJson, maxlength: 10 };
        document.body.innerHTML = componentHbs(testData);

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.getAttribute('maxlength')).toBe('10');
    });

    test('Should render minlength attribute', () => {
        const testData = { ...exampleJson, minlength: 3 };
        document.body.innerHTML = componentHbs(testData);

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.getAttribute('minlength')).toBe('3');
    });

    test('Should render autocomplete attribute off', () => {
        const testData = { ...exampleJson };
        document.body.innerHTML = componentHbs(testData);

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.getAttribute('autocomplete')).toBe('off');
    });

    test('Should render autocomplete attribute', () => {
        const testData = { ...exampleJson, autocomplete: 'shipping street-address' };
        document.body.innerHTML = componentHbs(testData);

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.getAttribute('autocomplete')).toBe('shipping street-address');
    });

    test('Should render novalidate attribute', () => {
        const testData = { ...exampleJson, novalidate: true };
        document.body.innerHTML = componentHbs(testData);

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.hasAttribute('novalidate')).toBeTruthy();
    });

    test('Should render novalidate attribute', () => {
        const testData = { ...exampleJson, novalidate: true };
        document.body.innerHTML = componentHbs(testData);

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.getAttribute('list')).toBe('my-datalist-id');
    });

    test('Should render multiple attribute', () => {
        const testData = { ...exampleJson, multiple: true };
        document.body.innerHTML = componentHbs(testData);

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.hasAttribute('multiple')).toBeTruthy();
    });

    test('Should render pattern attribute', () => {
        document.body.innerHTML = renderedComponent;

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.getAttribute('pattern')).toBe('[0-9]+');
    });

    test('Should render placeholder attribute', () => {
        const testData = { ...exampleJson, placeholder: 'Your name' };
        document.body.innerHTML = componentHbs(testData);

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.getAttribute('placeholder')).toBe('Your name');
    });

    test('Should render tabindex attribute', () => {
        const testData = { ...exampleJson, tabindex: '-1' };
        document.body.innerHTML = componentHbs(testData);

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.getAttribute('tabindex')).toBe('-1');
    });

    test('Should render title attribute', () => {
        const testData = { ...exampleJson, title: 'input title' };
        document.body.innerHTML = componentHbs(testData);

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.getAttribute('title')).toBe('input title');
    });

    test('Should render inputmode attribute', () => {
        const testData = { ...exampleJson, inputmode: 'email' };
        document.body.innerHTML = componentHbs(testData);

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.getAttribute('inputmode')).toBe('email');
    });

    test('Should render data attributes', () => {
        document.body.innerHTML = renderedComponent;

        const inputElement = document.querySelector('.eds-c-form__input');
        expect(inputElement.getAttribute('data-test')).toEqual('yes-test');
        expect(inputElement.getAttribute('data-track-context')).toEqual('springer-link');
        expect(inputElement.getAttribute('data-track-content-type')).toEqual('collection');
        expect(inputElement.getAttribute('data-track-label')).toEqual('collection');
    });

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