/*
** Copyright (C) 2021-2026 initMAX s.r.o.
**
** This program is free software: you can redistribute it and/or modify it under the terms of
** the GNU Affero General Public License as published by the Free Software Foundation, version 3.
**
** This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
** without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
** See the GNU Affero General Public License for more details.
**
** You should have received a copy of the GNU Affero General Public License along with this program.
** If not, see <https://www.gnu.org/licenses/>.
**/

/**
 * initMAX PRO-teaser - generic edition chrome for the FREE build of a widget.
 *
 * This file is OWNED by the CI library (tools/pro-teaser/) and injected into
 * every widget build by build-edition.py - widgets must NOT copy or edit it.
 * The PHP side (ProTeaser.php) emits a single
 *   window.initmaxProTeaser.apply(<form>, <config>)
 * call from the widget config form view. Config is built from the
 * `teaser_fields` declaration in features.yaml, so a widget author writes no
 * JS at all.
 *
 * In the FREE build the PRO fields render as native Zabbix controls but
 * disabled (greyed); this script greys them, drops a grey padlock to the RIGHT
 * of each control, and appends a single "Upgrade to PRO" link below the form.
 * Hovering the padlock opens a Zabbix hintbox describing the feature + the
 * upgrade link.
 *
 * Cross-version hintbox: 6.4+ reads the hint from `data-hintbox-contents`
 * (main.js: target.dataset.hintboxContents), 6.0/6.2 read it from the
 * immediate next `.hint-box` sibling (main.js: $target.next('.hint-box')).
 * We set BOTH every time, so one file covers Zabbix 6.0-7.4.
 *
 * @global window.initmaxProTeaser
 */
window.initmaxProTeaser = window.initmaxProTeaser || new class {

	/**
	 * @param {HTMLElement|string|null} form  the config form element, its id, or null (auto-resolve)
	 * @param {Object} config
	 * @param {string}   [config.logo_class]     edition logo css class (initmax-free|initmax-pro)
	 * @param {string[]} [config.disable_fields] field names to grey + lock (empty in PRO)
	 * @param {Object}   [config.hints]          field name -> hint html/text
	 * @param {string}   [config.upgrade_label]  upgrade link label
	 * @param {string}   [config.upgrade_url]    upgrade link href
	 */
	apply(form, config) {
		config = config || {};
		const root = this.resolveForm(form);
		if (root === null) {
			return;
		}

		if (config.logo_class) {
			this.addLogo(root, config.logo_class);
		}

		const fields = config.disable_fields || [];
		for (const name of fields) {
			for (const el of root.querySelectorAll(`[name="${name}"], [name="${name}[]"]`)) {
				el.disabled = true;
			}
			this.addLock(root, name, config);
		}

		this.addFooter(root, config, fields.length > 0);
	}

	resolveForm(form) {
		if (form instanceof HTMLElement) {
			return form;
		}
		if (typeof form === 'string' && form !== '') {
			const byId = document.getElementById(form);
			if (byId !== null) {
				return byId;
			}
		}
		return document.getElementById('widget-dialogue-form')
			?? document.querySelector('.modal-widget-configuration form')
			?? document.querySelector('.overlay-dialogue[data-dialogueid="widget_properties"] form');
	}

	addLogo(root, logo_class) {
		if (root.querySelector('.' + logo_class) !== null) {
			return;
		}
		const el = document.createElement('div');
		el.classList.add(logo_class);
		// Guarantee a visible (non-zero) box even on trees that don't load the
		// widget CSS: the v1/legacy tree has no manifest asset bundle, so the
		// .initmax-*:before image rule never applies there. On v2 the :before
		// pseudo-element supplies the 32px logo image; this min-height is just
		// a harmless floor.
		el.style.cssText = 'display:block;min-height:24px;';
		root.insertBefore(el, root.firstChild);
	}

	addLock(root, name, config) {
		const cell = this.findFieldCell(root, name);
		if (cell === null || cell.querySelector('.initmax-pro-lock') !== null) {
			return;
		}

		const contents = this.lockHint(name, config);

		const el = document.createElement('span');
		el.className = 'initmax-pro-lock';
		el.style.cssText = 'display:inline-flex;align-items:center;margin-left:8px;'
			+ 'vertical-align:middle;cursor:pointer;line-height:1;';
		el.innerHTML = this.lockSvg();
		// 6.4+ hintbox: reads the content from this data attribute.
		el.setAttribute('data-hintbox', '1');
		el.setAttribute('data-hintbox-static', '1');
		el.setAttribute('data-hintbox-contents', contents);
		cell.appendChild(el);

		// 6.0/6.2 hintbox: reads the content from the immediate next .hint-box
		// sibling instead of the data attribute. Hidden; harmless on 6.4+.
		const box = document.createElement('span');
		box.className = 'hint-box';
		box.style.display = 'none';
		box.innerHTML = contents;
		cell.appendChild(box);
	}

	// The hintbox body for one PRO field: what it does + an upgrade link.
	lockHint(name, config) {
		const hints = config.hints || {};
		const hint = hints[name] || '';
		const url = config.upgrade_url || '#';
		const label = config.upgrade_label || 'Upgrade to PRO';

		return '<div class="initmax-pro-hint">'
			+ '<div>' + this.esc(hint) + '</div>'
			+ '<div style="margin:8px 0 6px;border-top:1px solid rgba(0,0,0,.15);"></div>'
			+ '<a href="' + this.escAttr(url) + '" target="_blank" rel="noopener">'
			+ this.esc(label) + ' &rarr;</a>'
			+ '</div>';
	}

	addFooter(root, config, withUpgrade) {
		if (root.querySelector('.initmax-pro-footer') !== null) {
			return;
		}

		const footer = document.createElement('div');
		footer.className = 'initmax-pro-footer';
		footer.style.cssText = 'margin-top:12px;padding-top:10px;'
			+ 'border-top:1px solid rgba(0,0,0,.1);font-size:12px;';

		if (withUpgrade) {
			footer.appendChild(this.footerLink(
				config.upgrade_url || '#',
				config.upgrade_label || 'Upgrade to PRO',
				this.unlockSvg()
			));
		}

		// "Give us feedback" - both editions, deep-links to the portal
		// product page with the feedback dialog auto-opened.
		if (config.feedback_url) {
			if (withUpgrade) {
				const sep = document.createElement('span');
				sep.textContent = ' · ';
				sep.style.cssText = 'opacity:.35;margin:0 6px;';
				footer.appendChild(sep);
			}
			footer.appendChild(this.footerLink(
				config.feedback_url,
				config.feedback_label || 'Give us feedback',
				this.feedbackSvg()
			));
		}

		if (footer.childNodes.length > 0) {
			root.appendChild(footer);
		}
	}

	// Icon + label link for the config-form footer. The inline SVGs use
	// currentColor, so they follow the link colour in every Zabbix theme.
	footerLink(href, label, iconSvg) {
		const link = document.createElement('a');
		link.href = href;
		link.target = '_blank';
		link.rel = 'noopener';
		link.style.cssText = 'display:inline-flex;align-items:center;gap:4px;';
		link.innerHTML = iconSvg;
		link.appendChild(document.createTextNode(label));
		return link;
	}

	// Unlocked padlock - the PRO padlock silhouette with the shackle open.
	unlockSvg() {
		return '<svg viewBox="0 0 24 24" width="13" height="13" aria-hidden="true" focusable="false" style="vertical-align:-2px;">'
			+ '<path fill="currentColor" d="M12 2a5 5 0 0 1 5 5h-2a3 3 0 0 0-6 0v3h9a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H6'
			+ 'a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h1V7a5 5 0 0 1 5-5zm0 11.5a1.5 1.5 0 0 0-.75 2.8V18a.75.75 0 0 0 1.5 0'
			+ 'v-1.7a1.5 1.5 0 0 0-.75-2.8z"/></svg>';
	}

	// Pencil over a document - "write us something".
	feedbackSvg() {
		return '<svg viewBox="0 0 24 24" width="13" height="13" aria-hidden="true" focusable="false" style="vertical-align:-2px;">'
			+ '<path fill="currentColor" d="M4 4h10v2H6v12h12v-8h2v10H4V4zm16.7 1.3-7.4 7.4-2.6.6.6-2.6 7.4-7.4'
			+ 'a1.4 1.4 0 0 1 2 0 1.4 1.4 0 0 1 0 2z"/></svg>';
	}

	// Grey padlock as an inline SVG: vector + identical on every Zabbix version
	// (no icon-font dependency).
	lockSvg() {
		return '<svg viewBox="0 0 24 24" width="13" height="13" aria-hidden="true" focusable="false">'
			+ '<path fill="#888888" d="M12 2a5 5 0 0 0-5 5v3H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h12a2 2 0 0 0 '
			+ '2-2v-7a2 2 0 0 0-2-2h-1V7a5 5 0 0 0-5-5zm-3 5a3 3 0 0 1 6 0v3H9V7zm3 6.5a1.5 1.5 0 0 1 .75 '
			+ '2.8V18a.75.75 0 0 1-1.5 0v-1.7a1.5 1.5 0 0 1 .75-2.8z"/></svg>';
	}

	/**
	 * The container holding a field's control, across versions: 6.4+ form-grid
	 * (.form-field), 6.0 form-list (td.table-forms-td-right). The padlock is
	 * appended here so it sits to the RIGHT of the control.
	 */
	findFieldCell(root, name) {
		const ctrl = root.querySelector(`[name="${name}"], [name="${name}[]"]`);
		if (ctrl === null) {
			return null;
		}
		return ctrl.closest('.form-field, .table-forms-td-right, td') || ctrl.parentElement;
	}

	esc(s) {
		const d = document.createElement('div');
		d.textContent = s == null ? '' : String(s);
		return d.innerHTML;
	}

	escAttr(s) {
		return this.esc(s).replace(/"/g, '&quot;');
	}
}();
