const dataAttributesSchema = require('../eds-c-data-attributes/data/eds-c-data-attributes.schema.json');
const breadcrumbsSchema = require('../eds-c-breadcrumbs/data/eds-c-breadcrumbs.schema.json');
const buttonSchema = require('../eds-c-button/data/eds-c-button.schema.json');
const autocompleteSchema = require('../eds-c-autocomplete/data/eds-c-autocomplete.schema.json');
const inputSchema = require('../eds-c-input/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 handlebars = require('handlebars');
const {findTemplates} = require('../../development/tests/templateLoader.js');

findTemplates([
    'eds-c-hero',
    'eds-c-breadcrumbs',
    'eds-c-button',
    'eds-c-data-attributes',
    'eds-c-input',
    'eds-c-label',
    'eds-c-autocomplete',
    'eds-c-hint'
]).load(handlebars);

describe('Hero Test Utilities', () => {
    test('Hero test utilities are defined', () => {
        expect(validateWithDependencies).toBeDefined();
        expect(setupAxe).toBeDefined();
        expect(createVariantTests).toBeDefined();
    });
});

const validateWithDependencies = (schema, data) => {
    const Ajv = require('ajv');
    const ajv = new Ajv();
    
    [
        { name: 'eds-c-data-attributes', schema: dataAttributesSchema },
        { name: 'eds-c-breadcrumbs', schema: breadcrumbsSchema },
        { name: 'eds-c-button', schema: buttonSchema },
        { name: 'eds-c-autocomplete', schema: autocompleteSchema },
        { name: 'eds-c-input', schema: inputSchema },
        { name: 'eds-c-label', schema: labelSchema },
        { name: 'eds-c-hint', schema: hintSchema },
        { name: 'eds-c-error-message', schema: errorMessageSchema },
    ].forEach((dependency) => {
        ajv.addSchema(dependency.schema, dependency.name);
    });

    const validate = ajv.compile(schema);
    const valid = validate(data);

    if (!valid) {
        const errors = validate.errors.map((error) => `${error.instancePath}: ${error.message}`).join('\n');
        console.error('Schema validation errors:', errors);
        return false;
    }
    return valid;
};

const setupAxe = () => {
    const { configureAxe, toHaveNoViolations } = require('jest-axe');
    expect.extend(toHaveNoViolations);
    
    return configureAxe({
        rules: {
            region: { enabled: false },
            'aria-input-field-name': { enabled: false }
        }
    });
};

const createVariantTests = (variantName, schema, example, templateName) => {
    const template = `{{> ${templateName} }}`;
    const compiledTemplate = handlebars.compile(template);
    const axe = setupAxe();

    return {
        schemaValidation: () => {
            test(`${variantName} schema validates against ${variantName.toLowerCase()} example`, () => {
                const valid = validateWithDependencies(schema, example);
                expect(valid).toBeTruthy();
            });
        },

        accessibilityTest: () => {
            test(`${variantName} variant renders without errors`, async () => {
                const rendered = compiledTemplate(example);
                document.body.innerHTML = rendered;
                const container = document.querySelector('.eds-c-hero');
                expect(container).toBeTruthy();
                expect(await axe(rendered)).toHaveNoViolations();
            });
        },

        renderTest: (selector, condition = () => true) => {
            test(`${variantName} variant renders ${selector}`, () => {
                const rendered = compiledTemplate(example);
                document.body.innerHTML = rendered;
                if (condition(example)) {
                    const element = document.querySelector(selector);
                    expect(element).toBeTruthy();
                }
            });
        },

        /**
         * customTest(testName, testFn)
         *
         * Use this when you need both the rendered DOM and the example data
         * for assertions (IDs, names, ARIA, cross-checking example values, etc).
         *
         * - renderTest(selector) is sufficient for simple presence checks.
         * - Use customTest for more complex assertions that require access
         *   to the original example object as well as the compiled DOM.
         *
         * The helper compiles and injects the template into jsdom then calls:
         *   testFn(renderedHtmlString, exampleObject)
         */

        customTest: (testName, testFn) => {
            test(`${variantName} variant ${testName}`, () => {
                const rendered = compiledTemplate(example);
                document.body.innerHTML = rendered;
                testFn(rendered, example);
            });
        }
    };
};

module.exports = {
    validateWithDependencies,
    setupAxe,
    createVariantTests
};