/**
 * 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 { instanceSymbol } from "../../constants.mjs";
import { ATTRIBUTE_ROLE } from "../../dom/constants.mjs";
import {
	assembleMethodSymbol,
	registerCustomElement,
} from "../../dom/customelement.mjs";
import { typeOf } from "../../types/typeof.mjs";
import { Button } from "./button.mjs";
import { PopperButton } from "./popper-button.mjs";
import { ConfirmButtonStyleSheet } from "./stylesheet/confirm-button.mjs";
import { fireCustomEvent } from "../../dom/events.mjs";

import "./button.mjs";
import "./message-state-button.mjs";
import { PopperButtonStyleSheet } from "./stylesheet/popper-button.mjs";
import { StateButtonStyleSheet } from "./stylesheet/state-button.mjs";

export { ConfirmButton };

/**
 * @private
 * @type {symbol}
 */
const confirmButtonElementSymbol = Symbol("confirmButtonElement");

/**
 * @private
 * @type {symbol}
 */
const cancelButtonElementSymbol = Symbol("cancelButtonElement");

/**
 * A confirmation button control.
 *
 * @fragments /fragments/components/form/confirm-button/
 *
 * @example /examples/components/form/confirm-button-simple simple confirm button
 *
 * @issue https://localhost.alvine.dev:8440/development/issues/closed/283.html
 *
 * @since 1.5.0
 * @copyright Volker Schukai
 * @summary A two-step confirmation button for destructive or high-impact actions such as delete or publish.
 */
class ConfirmButton extends PopperButton {
	/**
	 * This method is called by the `instanceof` operator.
	 * @return {symbol}
	 * @since 2.1.0
	 */
	static get [instanceSymbol]() {
		return Symbol.for(
			"@schukai/monster/components/form/confirm-button@@instance",
		);
	}

	/**
	 * The individual configuration values can be found in the table.
	 *
	 * @property {Object} templates Template definitions
	 * @property {string} templates.main Main template
	 * @property {Object} labels Label definitions
	 * @property {string} labels.button Button label
	 * @property {string} labels.message Message label
	 * @property {string} labels.confirm Confirm label
	 * @property {string} labels.cancel Cancel label
	 * @property {Object} classes Class definitions
	 * @property {string} classes.confirmButton Confirm button class
	 * @property {string} classes.cancelButton Cancel button class
	 * @property {Object} actions Action definitions
	 * @property {function} actions.confirm Confirm action
	 * @property {function} actions.cancel Cancel action
	 */
	get defaults() {
		const obj = Object.assign({}, super.defaults, {
			templates: {
				main: getTemplate(),
			},
			labels: {
				button: '<slot name="button"></slot>',
				message: "<slot>Should I Stay or Should I Go?</slot>",
				confirm: '<slot name="confirm">Confirm</slot>',
				cancel: '<slot name="cancel">Cancel</slot>',
			},
		});

		obj["popper"]["strategy"] = "fixed";
		obj["classes"]["confirmButton"] = "monster-button-primary";
		obj["classes"]["cancelButton"] = "monster-button-secondary";
		obj["actions"]["cancel"] = (e) => {
			this.hideDialog();
		};

		obj["actions"]["confirm"] = () => {};

		return obj;
	}

	hideDialog() {
		super.hideDialog();
		this[confirmButtonElementSymbol].removeState();
		return this;
	}

	/**
	 *
	 * @return {PopperButton}
	 */
	[assembleMethodSymbol]() {
		super[assembleMethodSymbol]();
		initControlReferences.call(this);
		initEventhandler.call(this);
	}

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

	/**
	 * @return {Array}
	 */
	static getCSSStyleSheet() {
		const styles = PopperButton.getCSSStyleSheet();
		styles.push(ConfirmButtonStyleSheet);
		return styles;
	}

	/**
	 *
	 * @return {ConfirmButton}
	 */
	showDialog() {
		const confirmButtonClass = this.getOption("classes.confirmButton");
		if (confirmButtonClass) {
			this[confirmButtonElementSymbol].setOption(
				"classes.button",
				confirmButtonClass,
			);
		}

		const cancelButtonClass = this.getOption("classes.cancelButton");
		if (cancelButtonClass) {
			this[cancelButtonElementSymbol].setOption(
				"classes.button",
				cancelButtonClass,
			);
		}

		return super.showDialog();
	}

	/**
	 * Set the confirm button state
	 *
	 * @param {string} state
	 * @param {number} timeout
	 * @return {ConfirmButton}
	 */
	setConfirmButtonState(state, timeout) {
		this[confirmButtonElementSymbol].setState(state, timeout);
		return this;
	}

	/**
	 * Set and show the confirm button message
	 *
	 * @param {string} message
	 * @param {number} timeout
	 * @return {ConfirmButton}
	 */
	showConfirmButtonMessage(message, timeout) {
		this[confirmButtonElementSymbol].setMessage(message);
		setTimeout(() => {
			this[confirmButtonElementSymbol].showMessage(timeout);
		}, 0);
		return this;
	}
}

/**
 * @private
 * @param type
 * @return {function}
 */
function getAction(type) {
	const self = this;

	return function (event) {
		const callback = self.getOption(`actions.${type}`);
		if (typeOf(callback) !== "function") {
			return;
		}

		callback.call(this, event);
	};
}

/**
 * @private
 * @return {initEventhandler}
 * @fires ConfirmButton#monster-confirm
 * @fires ConfirmButton#monster-confirmed
 */
function initEventhandler() {
	this[cancelButtonElementSymbol].setOption(
		"clickEventType",
		this.getOption("clickEventType", ["click"]),
	);
	this[cancelButtonElementSymbol].setOption(
		"actions.click",
		getAction.call(this, "cancel"),
	);

	this[confirmButtonElementSymbol].setOption(
		"clickEventType",
		this.getOption("clickEventType", ["click"]),
	);
	this[confirmButtonElementSymbol].setOption("actions.click", () => {
		const callback = getAction.call(this, "confirm");
		fireCustomEvent(this, "monster-confirm", {
			button: this,
		});
		callback.call(this);
		fireCustomEvent(this, "monster-confirmed", {
			button: this,
		});
	});

	return this;
}

/**
 * @private
 * @return {Select}
 */
function initControlReferences() {
	this[confirmButtonElementSymbol] = this.shadowRoot.querySelector(
		`[${ATTRIBUTE_ROLE}=confirm]`,
	);
	this[cancelButtonElementSymbol] = this.shadowRoot.querySelector(
		`[${ATTRIBUTE_ROLE}=cancel]`,
	);
}

/**
 * @private
 * @return {string}
 */
function getTemplate() {
	// language=HTML
	return `

        <div data-monster-role="control" part="control">
            <button data-monster-attributes="disabled path:disabled | if:true, class path:classes.button"
                    data-monster-role="button"
                    part="button"
                    data-monster-replace="path:labels.button"></button>

            <div data-monster-role="popper" part="popper" tabindex="-1" class="monster-color-primary-1">
                <div data-monster-role="arrow"></div>
                <div part="message" class="flex" data-monster-replace="path:labels.message"></div>
                <div data-monster-role="decision">
                    <monster-message-state-button exportparts="monster-state-button:confirm-button,
                                          control:confirm-control,
                                          button-button:confirm-control-button,
                                          button-control:confirm-button-control,
                                          popper:confirm-popper,
                                          message:confirm-popper-message-message,
                                          icon:confirm-popper-message-icon,
                                          title:confirm-popper-message-title"
                                                  data-monster-attributes="data-monster-button-class path:classes.confirmButton"
                                                  data-monster-role="confirm" part="confirm">
                        <span data-monster-replace="path:labels.confirm"></span>
                    </monster-message-state-button>

                    <monster-button exportparts="button:cancel-button,control:cancel-control"
                                    data-monster-attributes="data-monster-button-class path:classes.cancelButton"
                                    data-monster-role="cancel" part="cancel">
                        <span data-monster-replace="path:labels.cancel"></span>
                    </monster-button>
                </div>
            </div>
        </div>
    `;
}

registerCustomElement(ConfirmButton);
