const fs = require('fs');
const path = require('path');
const Ajv = require("ajv");
const ajv = new Ajv();
const schema = require('./data/eds-c-input.schema.json');
const schemaInputInline = require('./data/eds-c-input-inline.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 exampleJsonInputInline = require('./data/eds-c-input-inline.example.json');
const filenames = fs.readdirSync(__dirname);
const componentTemplate = fs.readFileSync(path.resolve(__dirname, 'eds-c-input.hbs'), 'utf8');
const inputDefaultTemplate = fs.readFileSync(path.resolve(`${__dirname}/partials/`, 'eds-c-input-default.hbs'), 'utf8');
const inputInlineTemplate = fs.readFileSync(path.resolve(`${__dirname}/partials/`, 'eds-c-input-inline.hbs'), 'utf8');
const componentsDir = path.join(__dirname, '..');
const labelTemplatePath = path.resolve(componentsDir, 'eds-c-label', 'eds-c-label.hbs');
const labelTemplate = fs.readFileSync(labelTemplatePath, 'utf8');
const hintTemplatePath = path.resolve(componentsDir, 'eds-c-hint', 'eds-c-hint.hbs');
const hintTemplate = fs.readFileSync(hintTemplatePath, 'utf8');
const errorMessageTemplatePath = path.resolve(componentsDir, 'eds-c-error-message', 'eds-c-error-message.hbs');
const errorMessageTemplate = fs.readFileSync(errorMessageTemplatePath, 'utf8');
const buttonTemplatePath = path.resolve(componentsDir, 'eds-c-button', 'eds-c-button.hbs');
const buttonTemplate = fs.readFileSync(buttonTemplatePath, 'utf8');
const handlebars = require('handlebars');

// register the partials that are used inside the component main template
handlebars.registerPartial('eds-c-input-default', inputDefaultTemplate);
handlebars.registerPartial('eds-c-input-inline', inputInlineTemplate);

filenames.forEach(function (filename) {
    var matches = /^([^.]+).hbs$/.exec(filename);
    if (!matches) {
        return;
    }
    var name = matches[1];
    var template = fs.readFileSync(__dirname + '/' + filename, 'utf8');
    handlebars.registerPartial(name, template);
});

const componentHbs = handlebars.compile(errorMessageTemplate, hintTemplate, labelTemplate, componentTemplate, buttonTemplate);
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 }
        }
    });

    const componentSchemasAndDataExamples = [[schema, exampleJson], [schemaInputInline, exampleJsonInputInline]];
    test('Example data matches schema', () => {
        // Add other schema to Ajv instance
        ajv.addSchema(labelSchema, 'labelSchema');
        ajv.addSchema(hintSchema, 'hintSchema');
        ajv.addSchema(errorMessageSchema, 'errorMessageSchema');
        ajv.addSchema(buttonSchema, 'buttonSchema');

        componentSchemasAndDataExamples.forEach((item) => {
            const validate = ajv.compile(item[0]);
            const valid = validate(item[1]);
            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 can be compiled and rendered', () => {
        document.body.innerHTML = renderedComponent;
        const container = document.querySelector('*');
        expect(container).toBeDefined();
    });
    
    test('Template passes basic HTML accessibility', async () => {
        expect(await axe(renderedComponent)).toHaveNoViolations();
    });
});