/**
 * 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 { isArray, isInstance } from "../../../types/is.mjs";

export { Entry };

/**
 * The Entry class represents a single entry in a discussion thread.
 *
 * @copyright Volker Schukai
 * @summary A single entry in a discussion thread.
 */
class Entry extends Base {
	constructor({
		id,
		title,
		message,
		user,
		date,
		children,
		hiddenChildren,
		actions,
		collapsed,
		replyCount,
	} = {}) {
		super();

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

		if (id) this.id = id;
		if (title) this.title = title;
		if (message) this.message = message;
		if (user) this.user = user;
		if (date) this.date = date;
		if (children) this.children = children;
		if (hiddenChildren) this.hiddenChildren = hiddenChildren;
		if (actions) this.actions = actions;
		if (collapsed !== undefined) this.collapsed = collapsed;
		if (replyCount !== undefined) this.replyCount = replyCount;

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

	/**
	 * This method is called by the `instanceof` operator.
	 * @return {symbol}
	 */
	static get [instanceSymbol]() {
		return Symbol.for("@schukai/component-state/thread/entry");
	}

	/**
	 *
	 * @return {object}
	 */
	get internalDefaults() {
		return {
			id: null,
			title: null,
			message: null,
			user: null,
			date: null,
			children: [],
			hiddenChildren: [],
			actions: null,
			collapsed: null,
			replyCount: 0,
		};
	}

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

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

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

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

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

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

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

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

	/**
	 * @return {Date}
	 */
	get date() {
		return this.getInternal("date");
	}

	/**
	 * @param {string|Date} value
	 */
	set date(value) {
		if (!isInstance(value, Date)) {
			value = new Date(value);
		}
		this.setInternal("date", value);
	}

	/**
	 * @return {Array}
	 */
	get children() {
		return this.getInternal("children");
	}

	/**
	 * @param {Array} value
	 */
	set children(value) {
		this.setInternal("children", isArray(value) ? value : []);
	}

	/**
	 * @return {Array}
	 */
	get hiddenChildren() {
		return this.getInternal("hiddenChildren");
	}

	/**
	 * @param {Array} value
	 */
	set hiddenChildren(value) {
		this.setInternal("hiddenChildren", isArray(value) ? value : []);
	}

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

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

	/**
	 * @return {boolean}
	 */
	get collapsed() {
		return this.getInternal("collapsed");
	}

	/**
	 * @param {boolean} value
	 */
	set collapsed(value) {
		this.setInternal("collapsed", Boolean(value));
	}

	/**
	 * @return {number}
	 */
	get replyCount() {
		return this.getInternal("replyCount");
	}

	/**
	 * @param {number} value
	 */
	set replyCount(value) {
		const next = Number.isFinite(value) ? value : Number(value) || 0;
		this.setInternal("replyCount", next);
	}
}
