/**
 * 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 { Base } from "../../../types/base.mjs";
import { equipWithInternal } from "../../../types/internal.mjs";
import { instanceSymbol } from "../../../constants.mjs";
import { Observer } from "../../../types/observer.mjs";
import { ATTRIBUTE_DATATABLE_SORTABLE } from "../../constants.mjs";
import {
	validateIterable,
	validateInstance,
} from "../../../types/validate.mjs";
import { Formatter } from "../../../text/formatter.mjs";

export {
	Header,
	DIRECTION_ASC,
	DIRECTION_DESC,
	DIRECTION_NONE,
	createOrderStatement,
};

/**
 * small to large
 * @private
 * @type {string}
 */
const DIRECTION_ASC = "asc";

/**
 * large to small
 * @private
 * @type {string}
 */
const DIRECTION_DESC = "desc";

/**
 * no direction and no order statement
 *
 * @private
 * @type {string}
 */
const DIRECTION_NONE = "";

/**
 * The Header component is a basic class for the datatable component.
 *
 * @copyright Volker Schukai
 * @summary The Header component is a basic class for the datatable component.
 */
class Header extends Base {
	constructor() {
		super();

		/**
		 * - attachInternalObserver
		 * - detachInternalObserver
		 * - containsInternalObserver
		 * - setInternal
		 * - setInternals
		 * - getInternal
		 */
		equipWithInternal.call(this);

		this.attachInternalObserver(
			new Observer(() => {
				updateStruct.call(this);
			}),
		);
	}

	/**
	 * This method is called by the `instanceof` operator.
	 * @return {symbol}
	 */
	static get [instanceSymbol]() {
		return Symbol.for("@schukai/monster/components/datatable/header@@instance");
	}

	/**
	 *
	 * @return {object}
	 */
	get internalDefaults() {
		return {
			field: undefined,
			html: undefined,
			order: undefined,
			direction: undefined,
			label: undefined,
			labelKey: undefined,
			classes: undefined,
			index: undefined,
			mode: undefined,
			grid: undefined,
			features: undefined,
			orderTemplate: undefined,
			resizable: false,
			initialWidth: undefined,
		};
	}

	/**
	 */
	changeDirection() {
		let direction = this.getInternal("direction");
		if (direction === DIRECTION_ASC) {
			direction = DIRECTION_DESC;
		} else if (direction === DIRECTION_DESC) {
			direction = DIRECTION_NONE;
		} else {
			direction = DIRECTION_ASC;
		}
		this.setInternal("direction", direction);
	}

	/**
	 *
	 * @param {string} direction
	 */
	setDirection(direction) {
		this.setInternal("direction", direction);
	}

	/**
	 * @param {string} field
	 */
	set field(field) {
		this.setInternal("field", String(field));
	}

	/**
	 * @param {string} direction
	 */
	set direction(direction) {
		this.setInternal("direction", String(direction));
	}

	set labelKey(labelKey) {
		this.setInternal("labelKey", String(labelKey));
	}

	/**
	 * @param {string} label
	 */
	set label(label) {
		this.setInternal("label", String(label));
	}

	/**
	 * @param {string} classes
	 */
	set classes(classes) {
		this.setInternal("classes", String(classes));
	}

	/**
	 * @param {number} index
	 */
	set index(index) {
		this.setInternal("index", String(index));
	}

	set resizable(resizable) {
		this.setInternal("resizable", Boolean(resizable));
	}

	set initialWidth(initialWidth) {
		this.setInternal("initialWidth", String(initialWidth));
	}

	set orderTemplate(orderTemplate) {
		this.setInternal("orderTemplate", String(orderTemplate));
	}

	/**
	 * @return {string}
	 */
	get grid() {
		return this.getInternal("grid");
	}

	/**
	 * @return {string}
	 */
	get labelKey() {
		return this.getInternal("labelKey");
	}

	/**
	 * @return {string}
	 */
	get html() {
		return this.getInternal("html");
	}

	/**
	 * @return {string}
	 */
	get order() {
		return this.getInternal("order");
	}

	/**
	 * @return {string}
	 */
	get field() {
		return this.getInternal("field");
	}

	/**
	 * @return {string}
	 */
	get index() {
		return this.getInternal("index");
	}

	/**
	 * @return {string}
	 */
	get classes() {
		return this.getInternal("classes");
	}

	/**
	 * @return {string}
	 */
	get label() {
		return this.getInternal("label");
	}

	/**
	 * @return {string}
	 */
	get direction() {
		return this.getInternal("direction");
	}

	/**
	 * @return {string}
	 */
	get mode() {
		return this.getInternal("mode");
	}

	get resizable() {
		return this.getInternal("resizable");
	}

	get initialWidth() {
		return this.getInternal("initialWidth");
	}

	get orderTemplate() {
		return this.getInternal("orderTemplate");
	}
}

/**
 * @private
 * @param {Header[]} headers
 * @param {string} delimiter
 * @return {string}
 */
function createOrderStatement(headers, delimiter = ",") {
	validateIterable(headers);

	const oderStatement = [];
	for (const header of headers) {
		validateInstance(header, Header);
		const order = header.getInternal("order");

		if (!order) {
			continue;
		}
		oderStatement.push(order);
	}
	return oderStatement.join(delimiter);
}

/**
 * @private
 */
function updateStruct() {
	const label = this.getInternal("label");
	const direction = this.getInternal("direction");
	const field = this.getInternal("field");
	const isResizable = this.getInternal("resizable");

	let order = "";
	let htmlContent = label;

	if (field) {
		if (direction) {
			const tmpl = this.getInternal("orderTemplate");
			const formatter = new Formatter({
				direction: direction,
				label: label,
				field: field,
			});
			order = formatter.format(tmpl);
		}
		htmlContent = `<a href="#" ${ATTRIBUTE_DATATABLE_SORTABLE}="${order}">${label}</a>`;
	}

	if (isResizable) {
		const resizeHandleSVG = `<svg width="12" height="16" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><circle cx="9" cy="8" r="1.5"></circle><circle cx="9" cy="12" r="1.5"></circle><circle cx="9" cy="16" r="1.5"></circle><circle cx="15" cy="8" r="1.5"></circle><circle cx="15" cy="12" r="1.5"></circle><circle cx="15" cy="16" r="1.5"></circle></svg>`;
		htmlContent += `<div class="resize-handle" data-monster-role="resize-handle">${resizeHandleSVG}</div>`;
	}

	this.setInternal("order", order);
	this.setInternal("html", htmlContent);
}
