/**
 * 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.
 */

import { instanceSymbol } from "../../constants.mjs";
import { ATTRIBUTE_ROLE } from "../../dom/constants.mjs";
import { CustomControl } from "../../dom/customcontrol.mjs";
import {
	assembleMethodSymbol,
	registerCustomElement,
} from "../../dom/customelement.mjs";
import { PasswordStyleSheet } from "./stylesheet/password.mjs";
import { fireCustomEvent } from "../../dom/events.mjs";
import "./input-group.mjs";

export { Password };

/**
 * @private
 * @type {symbol}
 */
export const passwordElementSymbol = Symbol("passwordElement");

/**
 * @private
 * @type {symbol}
 */
export const visibleIconElementSymbol = Symbol("visibleIconElement");

/**
 * @private
 * @type {symbol}
 */
export const hiddenIconElementSymbol = Symbol("hiddenIconElement");

/**
 * @private
 * @type {symbol}
 */
export const inputElementSymbol = Symbol("inputIconElement");

/**
 * A password field
 *
 * @fragments /fragments/components/form/password
 *
 * @example /examples/components/form/password-simple
 *
 * @since 3.89.0
 * @copyright Volker Schukai
 * @summary A beautiful Password field that can make your life easier and also looks good.
 * @fires monster-password-hide
 * @fires monster-password-show
 */
class Password extends CustomControl {
	/**
	 * This method is called by the `instanceof` operator.
	 * @returns {symbol}
	 */
	static get [instanceSymbol]() {
		return Symbol.for("@schukai/monster/components/form/password@@instance");
	}

	/**
	 *
	 * @return {Components.Form.Password
	 */
	[assembleMethodSymbol]() {
		super[assembleMethodSymbol]();
		initControlReferences.call(this);
		initEventHandler.call(this);
		initPasswordState.call(this);
		return this;
	}

	/**
	 * The current value of the Switch
	 * @return {string}
	 */
	get value() {
		return this.getOption("value");
	}

	/**
	 * Set value
	 * @property {string} value
	 */
	set value(value) {
		this.setOption("value", value);
		this[inputElementSymbol].value = value;
		this.setFormValue(value);
	}

	/**
	 * 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 {string} templateMapping.hidden-icon The hidden icon template (without svg tag)
	 * @property {string} templateMapping.visible-icon The visible icon template (without svg tag)
	 * @property {string} type="password" The type of the input field
	 * @property {string} placeholder="" The placeholder of the input field
	 * @property {boolean} required=false The required state of the input field
	 * @property {string} autocomplete="off" The autocomplete state of the input field
	 * @property {string} inputmode="text" The inputmode state of the input field
	 * @property {Object} aria Aria attributes
	 * @property {boolean} aria.required=false The required state of the input field
	 * @property {string} aria.placeholder="" The placeholder of the input field
	 * @property {boolean} disabled=false Disabled state
	 */
	get defaults() {
		return Object.assign({}, super.defaults, {
			templates: {
				main: getTemplate(),
			},
			templateMapping: {
				"hidden-icon": `                    
                    <path d="M13.359 11.238C15.06 9.72 16 8 16 8s-3-5.5-8-5.5a7 7 0 0 0-2.79.588l.77.771A6 6 0 0 1 8 3.5c2.12 0 3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755q-.247.248-.517.486z"/>
                    <path d="M11.297 9.176a3.5 3.5 0 0 0-4.474-4.474l.823.823a2.5 2.5 0 0 1 2.829 2.829zm-2.943 1.299.822.822a3.5 3.5 0 0 1-4.474-4.474l.823.823a2.5 2.5 0 0 0 2.829 2.829"/>
                    <path d="M3.35 5.47q-.27.24-.518.487A13 13 0 0 0 1.172 8l.195.288c.335.48.83 1.12 1.465 1.755C4.121 11.332 5.881 12.5 8 12.5c.716 0 1.39-.133 2.02-.36l.77.772A7 7 0 0 1 8 13.5C3 13.5 0 8 0 8s.939-1.721 2.641-3.238l.708.709zm10.296 8.884-12-12 .708-.708 12 12z"/>`,
				"visible-icon": `
                    <path d="M16 8s-3-5.5-8-5.5S0 8 0 8s3 5.5 8 5.5S16 8 16 8M1.173 8a13 13 0 0 1 1.66-2.043C4.12 4.668 5.88 3.5 8 3.5s3.879 1.168 5.168 2.457A13 13 0 0 1 14.828 8q-.086.13-.195.288c-.335.48-.83 1.12-1.465 1.755C11.879 11.332 10.119 12.5 8 12.5s-3.879-1.168-5.168-2.457A13 13 0 0 1 1.172 8z"/>
                    <path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5M4.5 8a3.5 3.5 0 1 1 7 0 3.5 3.5 0 0 1-7 0"/>`,
			},
			type: "password",
			placeholder: "",
			required: false,
			autocomplete: "off",
			inputmode: "text",
			aria: {
				required: false,
				placeholder: "",
			},
			disabled: false,
			value: null,

			eventProcessing: true,
		});
	}

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

	/**
	 * @return {CSSStyleSheet[]}
	 */
	static getCSSStyleSheet() {
		return [PasswordStyleSheet];
	}
}

/**
 * @private
 * @return {initEventHandler}
 * @fires monster-password-hide
 * @fires monster-password-show
 */
function initEventHandler() {
	const self = this;
	const element = this[passwordElementSymbol];

	const type = "click";

	this[hiddenIconElementSymbol].addEventListener(type, function (event) {
		fireCustomEvent(self, "monster-password-show", {
			element: self,
		});

		requestAnimationFrame(() => {
			self[visibleIconElementSymbol].classList.remove("hidden");
			self[hiddenIconElementSymbol].classList.add("hidden");
			self.setOption("type", "text");
		});
	});

	this[visibleIconElementSymbol].addEventListener(type, function (event) {
		fireCustomEvent(self, "monster-password-hide", {
			element: self,
		});

		requestAnimationFrame(() => {
			self[visibleIconElementSymbol].classList.add("hidden");
			self[hiddenIconElementSymbol].classList.remove("hidden");
			self.setOption("type", "password");
		});
	});

	this[inputElementSymbol].addEventListener("input", function (event) {
		self.setFormValue(self.value);
		self.setOption("value", this.value);
	});

	return this;
}

/**
 * @private
 */
function initPasswordState() {
	if (this.getOption("type") === "password") {
		this[visibleIconElementSymbol].classList.add("hidden");
		this[hiddenIconElementSymbol].classList.remove("hidden");
	} else {
		this[visibleIconElementSymbol].classList.remove("hidden");
		this[hiddenIconElementSymbol].classList.add("hidden");
	}
}

/**
 * @private
 * @return {void}
 */
function initControlReferences() {
	this[passwordElementSymbol] = this.shadowRoot.querySelector(
		`[${ATTRIBUTE_ROLE}="control"]`,
	);

	this[visibleIconElementSymbol] = this.shadowRoot.querySelector(
		`[${ATTRIBUTE_ROLE}="visible-icon"]`,
	);

	this[hiddenIconElementSymbol] = this.shadowRoot.querySelector(
		`[${ATTRIBUTE_ROLE}="hidden-icon"]`,
	);

	this[inputElementSymbol] = this.shadowRoot.querySelector(
		`[${ATTRIBUTE_ROLE}="input"]`,
	);
}

/**
 * @private
 * @return {string}
 */
function getTemplate() {
	// language=HTML
	return `
        <div data-monster-role="control" part="control">
            <monster-input-group part="input-group">
                <input data-monster-role="input"
		       part="input"
                       style="border:0"
                       data-monster-attributes="
			    type path:type,
			    placeholder path:placeholder,
			    required path:required,
			    autocomplete path:autocomplete,
			    inputmode path:inputmode,
			    aria-required path:aria.required,
			    aria-placeholder path:aria.placeholder">
                <svg viewBox="0 0 16 16" data-monster-role="visible-icon" class="hidden">
                    \${visible-icon}
                </svg>
                <svg viewBox="0 0 16 16" data-monster-role="hidden-icon" class="hidden">
                    \${hidden-icon}
                </svg>
            </monster-input-group>

        </div>

    `;
}

registerCustomElement(Password);
