const schema = require('./data/eds-c-accordion.schema.json');
const schemaWithCheckbox = require('./data/eds-c-accordion-with-checkbox.schema.json');
const dataAttributesSchema = require('../eds-c-data-attributes/data/eds-c-data-attributes.schema.json');
const checkboxSchema = require('../eds-c-checkbox/data/eds-c-checkbox.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 inputSchema = require('../eds-c-input/data/eds-c-input.schema.json');
const exampleJson = require('./data/eds-c-accordion.example.json');
const exampleJsonWithCheckbox = require('./data/eds-c-accordion-with-checkbox.example.json');
const fs = require('node:fs');
const path = require('node:path');
const componentTemplate = '{{> eds-c-accordion }}';
const componentTemplateComposableWithCheckbox = '{{> eds-c-accordion-composable-with-checkbox }}';
const handlebars = require('handlebars');

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

const componentHbs = handlebars.compile(componentTemplate);
const componentHbsComposableWithCheckbox = handlebars.compile(componentTemplateComposableWithCheckbox);
const renderedComponent = componentHbs(exampleJson);
const renderedComponentComposableWithCheckbox = componentHbsComposableWithCheckbox(exampleJsonWithCheckbox);

describe('EDS accordion 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 valid = validateSchema(schema, exampleJson, [
			{ name: 'eds-c-data-attributes', schema: dataAttributesSchema }
		]);
		expect(valid).toBeTruthy();
	});

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

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

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

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('#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('Strip element should always be rendered in basic template (mobile navigation)', () => {
		document.body.innerHTML = componentHbs(exampleJson);
		const stripElement = document.querySelector('.eds-c-accordion__strip');
		expect(stripElement).not.toBeNull();
	});

	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');
	});
});

describe('Accordion with Checkbox Composable Variant', () => {
	const { configureAxe, toHaveNoViolations } = require('jest-axe');
	expect.extend(toHaveNoViolations);

	const axe = configureAxe({
		rules: {
			region: { enabled: false }
		}
	});

	test('Example data matches schema', () => {
		const valid = validateSchema(schemaWithCheckbox, exampleJsonWithCheckbox, [
			{ name: 'eds-c-checkbox', schema: checkboxSchema },
			{ name: 'eds-c-label', schema: labelSchema },
			{ name: 'eds-c-hint', schema: hintSchema },
			{ name: 'eds-c-error-message', schema: errorMessageSchema },
			{ name: 'eds-c-input', schema: inputSchema }
		]);
		expect(valid).toBeTruthy();
	});

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

	test('renders correctly with checkboxes', () => {
		const result = renderedComponentComposableWithCheckbox;
		expect(result).toContain('id="content-type-filter"');
		expect(result).toContain('Content type');
		expect(result).toContain('data-eds-c-accordion');
		expect(result).toContain('eds-c-accordion__content--grouped');
	});

	test('renders all checkboxes', () => {
		document.body.innerHTML = renderedComponentComposableWithCheckbox;
		const checkboxes = document.querySelectorAll('input[type="checkbox"]');
		expect(checkboxes.length).toBe(8);
	});

	test('checkbox labels match example data', () => {
		document.body.innerHTML = renderedComponentComposableWithCheckbox;
		const firstCheckboxLabel = document.querySelector('label[for="filter-article"]');
		expect(firstCheckboxLabel.textContent).toContain('Article (664,333)');
	});

	test('all checkboxes have the same name attribute', () => {
		document.body.innerHTML = renderedComponentComposableWithCheckbox;
		const checkboxes = document.querySelectorAll('input[type="checkbox"]');
		checkboxes.forEach(checkbox => {
			expect(checkbox.getAttribute('name')).toBe('contentType');
		});
	});

	test('accordion is open when open is true', () => {
		document.body.innerHTML = renderedComponentComposableWithCheckbox;
		const buttonElement = document.querySelector('.eds-c-accordion__button');
		expect(buttonElement.getAttribute('aria-expanded')).toBe('true');
	});

	test('data attributes are applied to button element', () => {
		document.body.innerHTML = renderedComponentComposableWithCheckbox;
		const buttonElement = document.querySelector('.eds-c-accordion__button');
		expect(buttonElement.getAttribute('data-test')).toBe('content-type-filter');
	});

	test('accordion has default variant class when variant is "default"', () => {
		document.body.innerHTML = renderedComponentComposableWithCheckbox;
		const accordionElement = document.querySelector('.eds-c-accordion');
		expect(accordionElement.classList.contains('eds-c-accordion--default')).toBe(true);
	});

	test('accordion has no variant class when variant is not specified', () => {
		const { variant, ...testData } = exampleJsonWithCheckbox;
		document.body.innerHTML = componentHbsComposableWithCheckbox(testData);
		const accordionElement = document.querySelector('.eds-c-accordion');
		expect(accordionElement.className).toBe('eds-c-accordion');
	});

	test('strip element is rendered when strip is true', () => {
		const testData = { ...exampleJsonWithCheckbox, strip: true };
		document.body.innerHTML = componentHbsComposableWithCheckbox(testData);
		const stripElement = document.querySelector('.eds-c-accordion__strip');
		expect(stripElement).not.toBeNull();
	});

	test('strip element is not rendered when strip is false or omitted', () => {
		const testData = { ...exampleJsonWithCheckbox, strip: false };
		document.body.innerHTML = componentHbsComposableWithCheckbox(testData);
		const stripElement = document.querySelector('.eds-c-accordion__strip');
		expect(stripElement).toBeNull();
	});

	test('content has expandable data attribute when enableShowMore is true', () => {
		const testData = { 
			...exampleJsonWithCheckbox, 
			enableShowMore: true,
			showMoreHeight: 300,
			showMoreText: 'Show more',
			showLessText: 'Show less'
		};
		document.body.innerHTML = componentHbsComposableWithCheckbox(testData);
		const contentElement = document.querySelector('.eds-c-accordion__content');
		expect(contentElement.hasAttribute('data-eds-c-accordion-expandable')).toBe(true);
		expect(contentElement.getAttribute('data-show-more-height')).toBe('300');
		expect(contentElement.getAttribute('data-show-more-text')).toBe('Show more');
		expect(contentElement.getAttribute('data-show-less-text')).toBe('Show less');
	});

	test('content does not have expandable data attribute when enableShowMore is false', () => {
		const testData = { ...exampleJsonWithCheckbox, enableShowMore: false };
		document.body.innerHTML = componentHbsComposableWithCheckbox(testData);
		const contentElement = document.querySelector('.eds-c-accordion__content');
		expect(contentElement.hasAttribute('data-eds-c-accordion-expandable')).toBe(false);
	});
});
