import { BnumLog } from '../classes/bnum_log.js';
import { Mel_Promise } from '../mel_promise.js';
import { MainIconHtml, MaterialSymbolHtml } from './html_icon.js';

/**
 * Représentation HTML d'une notification avec un timer
 * @extends {mel_html2}
 */
export class mel_html_timer extends mel_html2 {
	/**
	 * Constructeur de la classe
	 * @param {number} timer Temps en seconde
	 * @param {mel_html | mel_html[] | string} contents Texte écrit dans la notification
	 */
	constructor(timer, contents = null) {
		super('div', {});

		/**
		 * @type {mel_html | mel_html[] | string}
		 * Données par défaut
		 */
		this._original_contents = contents;
		/**
		 * @type {number}
		 * Temps en secondes
		 */
		this.timer = timer;
		/**
		 * @type {MelEvent}
		 * Actions lorsque le timer est fini
		 */
		this.ontimerfinished = new MelEvent();
	}

	/**
	 * Génère sous élément Jquery
	 * @param {{}} additionnal_attribs Attributs additionnels
	 * @returns {$}
	 */
	generate(additionnal_attribs = {}) {
		return super.generate(additionnal_attribs).init_timer(this);
	}

	/**
	 * Génère en élément Jquery puis l'attache à un élement jquery parent
	 * @param {$} $parent Parent de cet élément
	 * @param {{}} additionnal_attribs Attributs additionnels
	 * @returns {$} Element générer, pas le parent
	 */
	create($parent, additionnal_attribs = []) {
		return super.create($parent, additionnal_attribs).start_timer();
	}

	/**
	 * Ajoute la classe si elle n'éxiste pas déjà
	 * @param {string} html_class
	 * @returns Chaîne
	 */
	tryAddClass(html_class) {
		if (!this.hasClass(html_class)) return this.addClass(html_class);

		return this;
	}

	_before_generate() {
		super._before_generate();
		this.attribs['data-timer'] = this.timer;
		this.tryAddClass('mel-message-timer')
			.tryAddClass('ui')
			.tryAddClass('alert');

		//let html = this._generate_content();
		this.jcontents[0] = new mel_html2('p', {
			contents: this._original_contents,
		}); //html.addContent(this._generate_timer());
		this.jcontents[1] = this._generate_timer();
	}

	_generate_timer() {
		return new mel_html2('div', {
			attribs: {
				class: 'mel-message-timer-bckg',
			},
			contents: new mel_html('div', {
				class: 'mel-message-timer-fg',
				style: 'width:0',
			}),
		});
	}

	static _alert(alert_type, timer, contents = null) {
		timer = new mel_html_timer(timer, contents);
		timer.tryAddClass(`alert-${alert_type}`);

		return timer;
	}

	static Success(timer, contents = null) {
		return this._alert('success', timer, contents);
	}

	static Error(timer, contents = null) {
		return this._alert('danger', timer, contents);
	}

	static Warning(timer, contents = null) {
		return this._alert('warning', timer, contents);
	}

	static Info(timer, contents = null) {
		return this._alert('infos', timer, contents);
	}
}

/**
 * Représentation HTML d'une notification avec un timer.
 * Le timer peut être arrêter.
 * @extends {mel_html_timer}
 */
export class mel_cancellable_html_timer extends mel_html_timer {
	constructor(timer, { contents = null, cancel_icon = 'undo' }) {
		super(timer, contents);

		this.onstart = new MelEvent();
		this.oncancel = new MelEvent();
		this.cancel_icon = cancel_icon;
	}

	_before_generate() {
		super._before_generate();

		let html_start = new mel_html2('button', {
			attribs: {
				class: mel_button.html_base_class_full,
			},
			contents: new MainIconHtml('send', {}, {}),
		});

		html_start.addClass('mel-timer-start');
		html_start.addClass(MaterialSymbolHtml.get_class_fill_on_hover());

		html_start.onclick.add('start', e => {
			this.onstart.call(e);
		});

		let html_cancel = new mel_html2('button', {
			attribs: {
				class: mel_button.html_base_class_full,
			},
			contents: new MainIconHtml(this.cancel_icon, {}, {}),
		});

		html_cancel.addClass('mel-timer-cancel');
		html_cancel.addClass(MaterialSymbolHtml.get_class_fill_on_hover());

		html_cancel.onclick.add('cancel', e => {
			this.oncancel.call(e);
		});

		this.jcontents[2] = html_start;
		this.jcontents[3] = html_cancel;
	}

	/**
	 *
	 * @param {*} alert_type
	 * @param {*} timer
	 * @param {*} param2
	 * @returns {mel_cancellable_html_timer}
	 */
	static _alert(alert_type, timer, { contents = null, cancel_icon = 'undo' }) {
		timer = new mel_cancellable_html_timer(timer, { contents, cancel_icon });
		timer.tryAddClass(`alert-${alert_type}`);

		return timer;
	}

	static Success(timer, { contents = null, cancel_icon = 'undo' }) {
		return this._alert('success', timer, { contents, cancel_icon });
	}

	static Error(timer, { contents = null, cancel_icon = 'undo' }) {
		return this._alert('danger', timer, { contents, cancel_icon });
	}

	static Warning(timer, { contents = null, cancel_icon = 'undo' }) {
		return this._alert('warning', timer, { contents, cancel_icon });
	}

	static Info(timer, { contents = null, cancel_icon = 'undo' }) {
		return this._alert('infos', timer, { contents, cancel_icon });
	}
}

(function ($) {
	$.fn.extend({
		init_timer: function (html_datas) {
			if (this.hasClass('mel-message-timer')) {
				const timers = html_datas.ontimerfinished;
				this.init_timer.ontimerfinished = timers;
				BnumLog.info('Timer initialized !');
			}

			return this;
		},

		start_timer: function () {
			if (this.hasClass('mel-message-timer')) {
				const timer = +(this.data('timer') ?? 0);
				const timers = this.init_timer.ontimerfinished;

				new Mel_Promise(
					(promise, $element, ontimerfinished, timer) => {
						BnumLog.info('Timer started !');
						promise.start_resolving();

						promise.create_promise(
							{
								callback: async (
									child_promise,
									$element,
									ontimerfinished,
									timer,
								) => {
									let _break = false;
									let _skip = false;
									let $number = $element.parent().parent().find('.time-number');
									for (let index = 0; index <= timer; ++index) {
										if (!_break && true === this.start_timer._break) {
											_break = true;
											this.start_timer._break = false;
											break;
										}

										if (!_skip && true === this.start_timer._skip) {
											_skip = true;
											this.start_timer._skip = false;
											break;
										}

										$element.css('width', `${(index / timer) * 100}%`);
										await delay(1000);
										if ($number.length > 0) $number.text(timer - (index + 1));
									}

									if (_break) {
										BnumLog.info('Timer stopped !');
										this.remove();
										promise.abort();
									} else {
										this.remove();

										if (!!ontimerfinished && ontimerfinished.haveEvents()) {
											ontimerfinished.call($element.parent().parent());
										}

										BnumLog.info('Timer finished !');

										promise.resolve();
									}
								},
							},
							$element.find('.mel-message-timer-fg'),
							ontimerfinished,
							timer,
						);
					},
					this,
					timers,
					timer,
				);
			}

			return this;
		},

		break_timer: function () {
			if (this.hasClass('mel-message-timer')) {
				this.start_timer._break = true;
			}

			return this;
		},

		skip_timer: function () {
			if (this.hasClass('mel-message-timer')) {
				this.start_timer._skip = true;
			}

			return this;
		},

		destroy_timer: function () {
			if (this.hasClass('mel-message-timer')) {
				this.start_timer._break = null;
				this.init_timer.ontimerfinished = null;
			}

			return this;
		},
	});
})(jQuery);