/**
 * Copyright © Volker Schukai and all contributing authors, {{copyRightYear}}. All rights reserved.
 * Node module: @schukai/monster
 *
 * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
 * The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
 *
 * For those who do not wish to adhere to the AGPLv3, a commercial license is available.
 * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
 * For more information about purchasing a commercial license, please contact Volker Schukai.
 *
 * SPDX-License-Identifier: AGPL-3.0
 */

import {
	assembleMethodSymbol,
	registerCustomElement,
} from "../../dom/customelement.mjs";
import { DetailsStyleSheet } from "./stylesheet/details.mjs";
import { ATTRIBUTE_BUTTON_LABEL } from "../host/constants.mjs";
import { isString } from "../../types/is.mjs";
import { generateUniqueConfigKey } from "../host/util.mjs";
import { Collapse, nameSymbol } from "./collapse.mjs";
import { instanceSymbol } from "../../constants.mjs";
import { getLocaleOfDocument } from "../../dom/locale.mjs";

export { Details };

/**
 * @private
 * @type {symbol}
 */
const buttonElementSymbol = Symbol("buttonElement");

/**
 * @private
 * @type {symbol}
 */
const buttonEventHandlerSymbol = Symbol("buttonEventHandler");

/**
 * A Details component
 *
 * @fragments /fragments/components/layout/details/
 *
 * @example /examples/components/layout/details-simple
 * @example /examples/components/layout/details-with-label
 * @example /examples/components/layout/details-as-accordion
 * @example /examples/components/layout/details-with-your-own-design
 *
 * @since 3.74.0
 * @copyright Volker Schukai
 * @summary A details layout component for expandable content blocks and accessible accordion-like sections.
 */
class Details extends Collapse {
	/**
	 * This method is called by the `instanceof` operator.
	 * @return {symbol}
	 */
	static get [instanceSymbol]() {
		return Symbol.for("@schukai/monster/components/layout/details@@instance");
	}

	/**
	 *
	 */
	constructor() {
		super();
		// the name is only used for the host config and the event name
		this[nameSymbol] = "details";
	}

	/**
	 * To set the options via the HTML Tag, the attribute `data-monster-options` must be used.
	 * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
	 *
	 * The individual configuration values can be found in the table.
	 *
	 * @property {Object} templates Template definitions
	 * @property {string} templates.main Main template
	 * @property {Object} button Button configuration
	 * @property {string} button.label Button label
	 */
	get defaults() {
		return Object.assign({}, super.defaults, {
			templates: {
				main: getTemplate(),
			},
			labels: getTranslations(),
		});
	}

	/**
	 * @return {void}
	 */
	[assembleMethodSymbol]() {
		super[assembleMethodSymbol]();

		initButtonLabel.call(this);
		initControlReferences.call(this);
		initEventHandler.call(this);
	}

	/**
	 * @return {void}
	 */
	connectedCallback() {
		super.connectedCallback();

		const containDocument = this.shadowRoot;

		if (containDocument !== null) {
			const previousElement = this.previousElementSibling;
			if (previousElement && previousElement.tagName === "MONSTER-DETAILS") {
				this[buttonElementSymbol].style.borderTop = "0";
			}
		}
	}

	/**
	 * @return {string}
	 */
	static getTag() {
		return "monster-details";
	}

	/**
	 * @return {CSSStyleSheet[]}
	 */
	static getCSSStyleSheet() {
		const css = super.getCSSStyleSheet();
		css.push(DetailsStyleSheet);
		return css;
	}
}

/**
 * @private
 * @returns {object}
 */
function getTranslations() {
	const locale = getLocaleOfDocument();
	switch (locale.language) {
		case "de":
			return {
				button: "Details",
			};
		case "fr":
			return {
				button: "Détails",
			};
		case "sp":
			return {
				button: "Detalles",
			};
		case "it":
			return {
				button: "Dettagli",
			};
		case "pl":
			return {
				button: "Szczegóły",
			};
		case "no":
			return {
				button: "Detaljer",
			};
		case "dk":
			return {
				button: "Detaljer",
			};
		case "sw":
			return {
				button: "Detaljer",
			};
		default:
		case "en":
			return {
				button: "Details",
			};
	}
}

/**
 * @private
 * @return {Select}
 * @throws {Error} no shadow-root is defined
 */
function initControlReferences() {
	if (!this.shadowRoot) {
		throw new Error("no shadow-root is defined");
	}

	this[buttonElementSymbol] = this.shadowRoot.querySelector(
		"[data-monster-role=button]",
	);
}

/**
 * @private
 */
function initEventHandler() {
	if (!this.shadowRoot) {
		throw new Error("no shadow-root is defined");
	}

	this[buttonEventHandlerSymbol] = (event) => {
		this.toggle();
	};

	this[buttonElementSymbol].addEventListener(
		"click",
		this[buttonEventHandlerSymbol],
	);

	return this;
}

/**
 * @private
 * @return {string}
 */
function initButtonLabel() {
	let label;
	const setLabel = false;
	if (this.hasAttribute(ATTRIBUTE_BUTTON_LABEL)) {
		label = this.getAttribute(ATTRIBUTE_BUTTON_LABEL);
	} else {
		label = this.getOption("labels.button", "Details");
	}

	if (!isString(label)) {
		label = "";
	}

	if (label === "") {
		label = this.innerText;
	}

	label = label.trim();

	if (label === "") {
		label = this.getOption("labels.button", "Details");
	}

	if (label.length > 100) {
		label = `${label.substring(0, 99)}…`;
	}

	this.setAttribute(ATTRIBUTE_BUTTON_LABEL, label);
	this.setOption("labels.button", label);

	return label;
}

/**
 * @private
 * @return {string}
 */
function getConfigKey() {
	return generateUniqueConfigKey("details", this.id, "state");
}

/**
 * @private
 * @return {string}
 */
function getTemplate() {
	// language=HTML
	return `
        <div data-monster-role="control" part="control" class="overflow-hidden">
            <div data-monster-role="summary" part="summary">
                <button part="button" data-monster-attributes="class path:classes.button"
                        data-monster-role="button"
                        data-monster-replace="path:labels.button | default:click me">click me
                </button>
            </div>
            <div data-monster-role="detail">
                <div data-monster-attributes="class path:classes.container" part="container"
                     data-monster-role="container">
                    <slot part="slot"></slot>
                </div>
                <div part="deco-line" class="deco-line" data-monster-role="deco"></div>
            </div>
        </div>`;
}

registerCustomElement(Details);
