const fs = require('node:fs');
const path = require('node:path');
const handlebars = require('handlebars');

const schema = require('./data/eds-c-copy-to-clipboard.schema.json');
const buttonSchema = require('../eds-c-button/data/eds-c-button.schema.json');

const visibleLabelWithFeedbackOnLabel = require('./data/eds-c-copy-to-clipboard--visible-label-label-feedback.example.json');
const hiddenLabelWithFeedbackOnButton = require('./data/eds-c-copy-to-clipboard--hidden-label-button-feedback.example.json');
const copyFromExternalParagraphSource = require('./data/eds-c-copy-to-clipboard--external-text.example.json');
const copyFromExternalTextareaSource = require('./data/eds-c-copy-to-clipboard--external-textarea.example.json');


const dataAttributesSchema = require('../eds-c-data-attributes/data/eds-c-data-attributes.schema.json');
const { findTemplates } = require('../../development/tests/templateLoader.js');
const { validateSchema } = require('../../development/tests/validate-schema');

const componentTemplate = '{{> eds-c-copy-to-clipboard }}';
findTemplates(['eds-c-copy-to-clipboard', 'eds-c-button', 'eds-c-data-attributes']).load(handlebars);

describe('EDS copy to clipboard component validation', () => {
	test('Docs file exists', () => {
		const exists = fs.existsSync(path.resolve(__dirname, 'docs.md'));
		expect(exists).toBe(true);
	});

	test('Example data matches schema', () => {
		const valid = validateSchema(schema, visibleLabelWithFeedbackOnLabel, [
			{ name: 'eds-c-button', schema: buttonSchema },
			{ name: 'eds-c-data-attributes', schema: dataAttributesSchema }
		]);
		expect(valid).toBeTruthy();
	});

	describe('Copy to clipboard component partial tests', () => {
		describe.each([
			{
				variantTitle: 'Visible label with feedback on label',
				data: visibleLabelWithFeedbackOnLabel,
				template: componentTemplate
			},
			{
				variantTitle: 'Hidden label with feedback on button',
				data: hiddenLabelWithFeedbackOnButton,
				template: componentTemplate
			},
			{
				variantTitle: 'Copy from external paragraph source',
				data: copyFromExternalParagraphSource,
				template: `
				<div
					role="status"
					aria-live="polite"
					class="u-visually-hidden"
					{{#with feedback}}
						data-live-region-text-on-success="{{liveRegionTextOnSuccess}}"
						data-live-region-text-on-error="{{liveRegionTextOnError}}"
					{{/with}}
					data-component-copytoclipboard-live-region="{{componentUID}}">
				</div>
				<p id="text-to-copy-to-clipboard" data-component-copytoclipboard-text-to-copy="{{componentUID}}">
					Our recent study published in Nature Aging reveals how the gut microbiota metabolite phenylacetylglutamine (PAGln) accelerates cellular senescence, inducing DNA damage and mitochondrial dysfunction. This insight could lead to potential anti-aging therapies.
				</p>
				{{> eds-c-copy-to-clipboard }}
                `
			},
			{
				variantTitle: 'Copy from external textarea source',
				data: copyFromExternalTextareaSource,
				template: `
				<div>
					<label for="research-brief-input">Research brief</label>
					<div
						role="status"
						aria-live="polite"
						class="u-visually-hidden"
						{{#with feedback}}
							data-live-region-text-on-success="{{liveRegionTextOnSuccess}}"
							data-live-region-text-on-error="{{liveRegionTextOnError}}"
						{{/with}}
						data-component-copytoclipboard-live-region="{{componentUID}}">
					</div>
					<textarea id="research-brief-input" cols="55" rows="10" data-component-copytoclipboard-text-to-copy="{{componentUID}}">
						The heterogeneity of human aging is not fully explained by
				genetic variation, suggesting that external factors like gut
				microbiota may influence the aging process. Previous studies have
				shown that gut microbiota changes with age, potentially affecting
				the development of age-related diseases. However, the impact of
				microbiota-related metabolites on physiological aging remains
				unclear. Now in our new article, we explore the role of the gut
				microbiota-derived metabolite phenylacetylglutamine (PAGln) in
				promoting cellular senescence and its potential as a target for
				anti-aging therapies...
					</textarea>
				</div>
				{{> eds-c-copy-to-clipboard }}
                `
			}
		])('Variant: $variantTitle', ({ _variantTitle, data, template }) => {
			let copyToClipboardWrapper;
			let copyToClipboardLabel;
			let copyToClipboardFormField;
			let copyToClipboardLiveRegion;
			let copyToClipboardInput;
			let copyToClipboardControl;

			const {
				componentUID,
				inputField,
				feedback,
				button
			} = data;

			beforeAll(() => {
				const hbsTemplate = handlebars.compile(template);
				document.body.innerHTML = hbsTemplate(data);

				copyToClipboardWrapper = document.querySelector(`[data-test="copy-to-clipboard"]`);
				copyToClipboardFormField = copyToClipboardWrapper.querySelector('[data-test="copy-to-clipboard-form-field"]');
				if (copyToClipboardFormField) {
					copyToClipboardLabel = copyToClipboardFormField.querySelector('label');
				}
				copyToClipboardLiveRegion = document.querySelector(`[data-component-copytoclipboard-live-region="${componentUID}"]`);
				copyToClipboardInput = document.querySelector(`[data-component-copytoclipboard-text-to-copy="${componentUID}"]`);
				copyToClipboardControl = copyToClipboardWrapper.querySelector('[data-test="copy-to-clipboard-control"]');
			});

			it('sets the `data-component-copytoclipboard-wrapper` attribute of the wrapper to `componentUID`', () => {
				expect(copyToClipboardWrapper).not.toBe(null);
				expect(copyToClipboardWrapper.dataset.componentCopytoclipboardWrapper).toEqual(componentUID);
			});

			describe('Accessibility features', () => {
                it('includes an ARIA live region with `polite` politeness setting', () => {
                    expect(copyToClipboardLiveRegion.getAttribute('role')).toEqual('status');
				    expect(copyToClipboardLiveRegion.getAttribute('aria-live')).toEqual('polite');
                });

				it('sets the `data-component-copytoclipboard-live-region` attribute of the live region to `componentUID`', () => {
					expect(copyToClipboardLiveRegion.dataset.componentCopytoclipboardLiveRegion).toEqual(componentUID);
				});

				it('sets the `data-live-region-text-on-success` attribute of the live region to `feedback.liveRegionTextOnSuccess`', () => {
					expect(copyToClipboardLiveRegion.dataset.liveRegionTextOnSuccess).toEqual(feedback.liveRegionTextOnSuccess);
				});

				it('sets the `data-live-region-text-on-error` attribute of the live region to `feedback.liveRegionTextOnError`', () => {
					expect(copyToClipboardLiveRegion.dataset.liveRegionTextOnError).toEqual(feedback.liveRegionTextOnError);
				});

				if (button.ariaLabelledBy) {
					it('sets the `data-component-copytoclipboard-button-aria-labelledby` attribute of the control element to `button.ariaLabelledBy`', () => {
						expect(copyToClipboardControl.dataset.componentCopytoclipboardButtonAriaLabelledby).toEqual(button.ariaLabelledBy);
					});

					if (button.ariaLabel) {
						it('does not set the `data-component-copytoclipboard-button-aria-label` attribute of the control element to `button.ariaLabel` if `button.ariaLabelledBy` is also provided', () => {
							expect(copyToClipboardControl.dataset.componentCopytoclipboardButtonAriaLabel).toBe(null);
						});
					}
				}

				if (button.ariaLabel) {
					it('sets the `data-component-copytoclipboard-button-aria-label` attribute of the control element to `button.ariaLabel`', () => {
						expect(copyToClipboardControl.dataset.componentCopytoclipboardButtonAriaLabel).toEqual(button.ariaLabel);
					});
				}
			});

			it('sets the `data-component-copytoclipboard-text-to-copy` attribute of the input to `componentUID`', () => {
				expect(copyToClipboardInput.dataset.componentCopytoclipboardTextToCopy).toEqual(componentUID);
			});

			if (inputField) {
				it('applies the `inputField.maxWidth` to the `style` attribute of the form field', () => {
					expect(copyToClipboardFormField.getAttribute('style')).toMatch(`--copy-to-clipboard-field-max-width: ${inputField.maxWidth};`);
				});

				it('sets the `for` attribute of the label to `inputField.inputId`', () => {
					expect(copyToClipboardLabel.getAttribute('for')).toEqual(inputField.inputId);
				});

				it('sets the `id` attribute of the label to `${componentUID}-input-label`', () => {
					expect(copyToClipboardLabel.getAttribute('id')).toEqual(`${componentUID}-input-label`);
				});

				if (inputField.label.cssClass !== undefined) {
					it('applies the `inputField.label.cssClass` to the `class` attribute of the label', () => {
						expect(copyToClipboardLabel.classList.contains(inputField.label.cssClass)).toBe(true);
					});
				}

				it('sets the `inputField.label.text` as the content the label span', () => {
					expect(copyToClipboardLabel.textContent.trim()).toMatch(inputField.label.text);
				});

				it('sets the `id` attribute of the input to `inputField.inputId`', () => {
					expect(copyToClipboardInput.getAttribute('id')).toEqual(inputField.inputId);
				});

				it('sets the `value` attribute of the input to `inputField.value`', () => {
					expect(copyToClipboardInput.getAttribute('value')).toEqual(inputField.value);
				});
			}

			it('sets the `data-component-copytoclipboard-control` attribute of the control element to `componentUID`', () => {
				expect(copyToClipboardControl.dataset.componentCopytoclipboardControl).toEqual(componentUID);
			});

			if (feedback.buttonTextOnSuccess !== undefined) {
				it('sets the `data-button-text-on-success` attribute of the control element to `feedback.buttonTextOnSuccess`', () => {
					expect(copyToClipboardControl.dataset.buttonTextOnSuccess).toEqual(feedback.buttonTextOnSuccess);
				});
			}

			if (feedback.buttonTextOnError !== undefined) {
				it('sets the `data-button-text-on-error` attribute of the control element to `feedback.buttonTextOnError`', () => {
					expect(copyToClipboardControl.dataset.buttonTextOnError).toEqual(feedback.buttonTextOnError);
				});
			}

			if (feedback.uiFeedbackDuration !== undefined) {
				it('sets the `data-ui-feedback-duration` attribute of the wrapper element to `feedback.uiFeedbackDuration`', () => {
					expect(copyToClipboardWrapper.dataset.uiFeedbackDuration).toEqual(feedback.uiFeedbackDuration.toString());
				});
			}
		});
	});
});
