<?php
/**
 * Mersal Suite — shared settings fields.
 *
 * One properly-built editor for "a list of message wordings", used by every
 * Mersal plugin so the three of them look and behave the same.
 *
 * It replaces the arrangement these lists started life with: a single textarea
 * where wordings were separated by blank lines. That asked the shop to keep an
 * invisible convention in their head, gave no way to reorder or count anything,
 * and silently merged two wordings the moment somebody deleted a blank line.
 *
 * Like the rest of the Suite SDK this file ships inside every plugin and only
 * the newest copy is ever loaded.
 *
 * @package Mersal_Suite
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( class_exists( 'Mersal_Suite_Fields' ) ) {
	return;
}

/**
 * Shared settings fields.
 */
class Mersal_Suite_Fields {

	/** @var bool Whether the stylesheet and behaviour have been printed. */
	private static $printed = false;

	/**
	 * Render a message-list editor.
	 *
	 * @param array $args {
	 *     @type string $name         POST name; each row posts as `name[]`.
	 *     @type array  $items        Current wordings.
	 *     @type array  $defaults     The shipped set, offered as "restore".
	 *     @type string $title        Card title.
	 *     @type string $desc         Card subtitle.
	 *     @type string $icon         Material Symbols name.
	 *     @type string $hint         Footnote under the list.
	 *     @type string $lang         'ar' | 'en'.
	 *     @type int    $rows         Textarea rows.
	 *     @type array  $placeholders token => label chips that insert at the cursor.
	 *     @type string $pin_name     Optional radio name, to mark one wording as the one to use.
	 *     @type int    $pin_value    Currently pinned index.
	 *     @type int    $pin_offset   What index the first row counts as (default 0).
	 *     @type string $pin_label    Label on the pin control.
	 *     @type bool   $pin_hidden   Start the pin controls hidden (a mode switch reveals them).
	 *     @type int    $max          Most wordings allowed.
	 *     @type string $add_label    Label on the add button.
	 * }
	 */
	public static function message_list( array $args ) {
		$a = wp_parse_args(
			$args,
			array(
				'name'         => '',
				'items'        => array(),
				'defaults'     => array(),
				'title'        => '',
				'desc'         => '',
				'icon'         => 'forum',
				'hint'         => '',
				'lang'         => 'ar',
				'rows'         => 3,
				'placeholders' => array(),
				'pin_name'     => '',
				'pin_value'    => 0,
				'pin_offset'   => 0,
				'pin_label'    => '',
				'pin_hidden'   => false,
				'max'          => 20,
				'add_label'    => '',
			)
		);

		if ( '' === $a['name'] ) {
			return;
		}

		$ar    = 'ar' === $a['lang'];
		$items = array_values( array_filter( array_map( 'strval', (array) $a['items'] ), 'strlen' ) );
		if ( empty( $items ) ) {
			$items = array_values( (array) $a['defaults'] );
		}

		$uid = 'msl' . substr( md5( $a['name'] ), 0, 8 );
		$t   = self::strings( $ar );

		self::print_assets();
		?>
		<div class="ms-list" data-ms-list="<?php echo esc_attr( $uid ); ?>"
			data-ms-name="<?php echo esc_attr( $a['name'] ); ?>"
			data-ms-rows="<?php echo (int) $a['rows']; ?>"
			data-ms-max="<?php echo (int) $a['max']; ?>"
			data-ms-pin="<?php echo esc_attr( $a['pin_name'] ); ?>"
			data-ms-pin-offset="<?php echo (int) $a['pin_offset']; ?>"
			data-ms-confirm="<?php echo esc_attr( $t['confirm'] ); ?>">

			<div class="ms-list-head">
				<div class="ms-list-ico"><span class="mi msym"><?php echo esc_html( $a['icon'] ); ?></span></div>
				<div class="ms-list-t">
					<b><?php echo esc_html( $a['title'] ); ?></b>
					<?php if ( $a['desc'] ) : ?><span><?php echo esc_html( $a['desc'] ); ?></span><?php endif; ?>
				</div>
				<span class="ms-list-count" data-ms-count><?php echo esc_html( sprintf( $t['count'], count( $items ) ) ); ?></span>
			</div>

			<?php if ( ! empty( $a['placeholders'] ) ) : ?>
				<div class="ms-list-chips">
					<span class="ms-chips-l"><?php echo esc_html( $t['insert'] ); ?></span>
					<?php foreach ( $a['placeholders'] as $code => $label ) : ?>
						<button type="button" class="ms-chip" data-ms-chip="<?php echo esc_attr( $code ); ?>" title="<?php echo esc_attr( $label ); ?>"><?php echo esc_html( trim( (string) $code, '{}' ) ); ?></button>
					<?php endforeach; ?>
				</div>
			<?php endif; ?>

			<div class="ms-list-rows" data-ms-rows-box>
				<?php foreach ( $items as $i => $body ) : ?>
					<?php
					self::row(
						$a,
						$i,
						$body,
						$t,
						count( $items )
					);
					?>
				<?php endforeach; ?>
			</div>

			<div class="ms-list-empty" data-ms-empty<?php echo $items ? ' hidden' : ''; ?>>
				<span class="mi msym">inbox</span>
				<span><?php echo esc_html( $t['empty'] ); ?></span>
			</div>

			<div class="ms-list-foot">
				<button type="button" class="ms-btn primary" data-ms-add>
					<span class="mi msym">add</span><?php echo esc_html( $a['add_label'] ? $a['add_label'] : $t['add'] ); ?>
				</button>
				<?php if ( ! empty( $a['defaults'] ) ) : ?>
					<button type="button" class="ms-btn" data-ms-restore
						data-ms-defaults="<?php echo esc_attr( wp_json_encode( array_values( (array) $a['defaults'] ) ) ); ?>">
						<span class="mi msym">restart_alt</span><?php echo esc_html( $t['restore'] ); ?>
					</button>
				<?php endif; ?>
			</div>

			<?php if ( $a['hint'] ) : ?>
				<p class="ms-list-hint"><?php echo esc_html( $a['hint'] ); ?></p>
			<?php endif; ?>

			<?php
			// An empty list must still post something, or "delete them all" would
			// read as "field absent" and the sanitiser would keep the old values.
			?>
			<input type="hidden" name="<?php echo esc_attr( $a['name'] ); ?>[__present]" value="1">
		</div>
		<?php
	}

	/**
	 * One wording row.
	 *
	 * @param array  $a     Field args.
	 * @param int    $i     Index.
	 * @param string $body  Wording.
	 * @param array  $t     Strings.
	 * @param int    $total Row count.
	 */
	private static function row( array $a, $i, $body, array $t, $total ) {
		$pin_idx = (int) $a['pin_offset'] + (int) $i;
		?>
		<div class="ms-row" data-ms-row>
			<div class="ms-row-top">
				<span class="ms-row-n" data-ms-n><?php echo esc_html( sprintf( $t['nth'], $i + 1 ) ); ?></span>

				<?php if ( $a['pin_name'] ) : ?>
					<label class="ms-row-pin" data-ms-pin-wrap<?php echo $a['pin_hidden'] ? ' style="display:none;"' : ''; ?>>
						<input type="radio" name="<?php echo esc_attr( $a['pin_name'] ); ?>" value="<?php echo esc_attr( $pin_idx ); ?>" <?php checked( (int) $a['pin_value'], $pin_idx ); ?>>
						<span><?php echo esc_html( $a['pin_label'] ? $a['pin_label'] : $t['pin'] ); ?></span>
					</label>
				<?php endif; ?>

				<div class="ms-row-tools">
					<button type="button" class="ms-icon" data-ms-up title="<?php echo esc_attr( $t['up'] ); ?>"><span class="mi msym">arrow_upward</span></button>
					<button type="button" class="ms-icon" data-ms-down title="<?php echo esc_attr( $t['down'] ); ?>"><span class="mi msym">arrow_downward</span></button>
					<button type="button" class="ms-icon danger" data-ms-del title="<?php echo esc_attr( $t['remove'] ); ?>"><span class="mi msym">delete</span></button>
				</div>
			</div>
			<textarea class="ms-row-ta" rows="<?php echo (int) $a['rows']; ?>" name="<?php echo esc_attr( $a['name'] ); ?>[]" placeholder="<?php echo esc_attr( $t['ph'] ); ?>"><?php echo esc_textarea( $body ); ?></textarea>
		</div>
		<?php
	}

	/**
	 * UI strings.
	 *
	 * @param bool $ar Arabic?
	 * @return array<string,string>
	 */
	private static function strings( $ar ) {
		return $ar
			? array(
				'count'   => '%d صيغة',
				'nth'     => 'الصيغة %d',
				'add'     => 'إضافة صيغة',
				'restore' => 'استعادة الصيغ الجاهزة',
				'remove'  => 'حذف',
				'up'      => 'تحريك لأعلى',
				'down'    => 'تحريك لأسفل',
				'pin'     => 'استخدم دي',
				'empty'   => 'مفيش صيغ لسه — ضيف واحدة أو استعِد الجاهزة.',
				'ph'      => 'اكتب نص الرسالة…',
				'insert'  => 'إدراج:',
				'confirm' => 'استبدال كل الصيغ بالصيغ الجاهزة؟',
			)
			: array(
				'count'   => '%d wordings',
				'nth'     => 'Wording %d',
				'add'     => 'Add a wording',
				'restore' => 'Restore the ready-made set',
				'remove'  => 'Remove',
				'up'      => 'Move up',
				'down'    => 'Move down',
				'pin'     => 'Use this one',
				'empty'   => 'No wordings yet — add one, or restore the ready-made set.',
				'ph'      => 'Write the message…',
				'insert'  => 'Insert:',
				'confirm' => 'Replace every wording with the ready-made set?',
			);
	}

	/**
	 * Print the stylesheet and behaviour once per page.
	 */
	private static function print_assets() {
		if ( self::$printed ) {
			return;
		}
		self::$printed = true;
		?>
		<style id="mersal-suite-fields-css">
		.ms-list { background: var(--surface, #fff); border: 1px solid var(--border, #e7e3d8); border-radius: 16px; padding: 18px; margin-bottom: 18px; }
		.ms-list-head { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
		.ms-list-ico { width: 38px; height: 38px; flex: 0 0 38px; border-radius: 11px; display: grid; place-items: center; background: var(--accent-soft, #dcefe3); color: var(--accent, #0f7a4a); }
		.ms-list-ico .mi { font-size: 21px; }
		.ms-list-t { flex: 1; min-width: 0; }
		.ms-list-t b { display: block; font-size: 14.5px; color: var(--fg-1, #16241d); }
		.ms-list-t span { display: block; font-size: 12.5px; color: var(--fg-2, #51605a); margin-top: 2px; line-height: 1.6; }
		.ms-list-count { flex: 0 0 auto; font-size: 11.5px; font-weight: 700; color: var(--accent, #0f7a4a); background: var(--accent-soft, #dcefe3); padding: 4px 10px; border-radius: 999px; white-space: nowrap; }

		.ms-list-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: 12px; }
		.ms-chips-l { font-size: 12px; color: var(--fg-3, #8a978f); }
		.ms-chip { border: 1px solid var(--border, #e7e3d8); background: var(--surface-2, #fafaf5); color: var(--fg-2, #51605a); border-radius: 999px; padding: 3px 10px; font-size: 11.5px; cursor: pointer; font-family: inherit; }
		.ms-chip:hover { border-color: var(--accent, #0f7a4a); color: var(--accent, #0f7a4a); }

		.ms-list-rows { display: flex; flex-direction: column; gap: 10px; }
		.ms-row { border: 1px solid var(--border, #e7e3d8); border-radius: 12px; background: var(--surface-2, #fafaf5); padding: 11px 12px; }
		.ms-row-top { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; flex-wrap: wrap; }
		.ms-row-n { font-size: 12px; font-weight: 700; color: var(--fg-1, #16241d); background: var(--surface-3, #f1efe8); padding: 3px 9px; border-radius: 999px; }
		.ms-row-pin { display: inline-flex; align-items: center; gap: 5px; font-size: 12px; color: var(--fg-2, #51605a); cursor: pointer; }
		.ms-row-tools { display: flex; align-items: center; gap: 4px; margin-inline-start: auto; }
		.ms-icon { width: 28px; height: 28px; border-radius: 8px; border: 1px solid transparent; background: transparent; color: var(--fg-3, #8a978f); display: grid; place-items: center; cursor: pointer; }
		.ms-icon .mi { font-size: 17px; }
		.ms-icon:hover { background: var(--surface-3, #f1efe8); color: var(--fg-1, #16241d); }
		.ms-icon.danger:hover { background: var(--danger-soft, #fbe2df); color: var(--danger, #d8524a); }
		.ms-icon[disabled] { opacity: .35; cursor: default; }
		.ms-icon[disabled]:hover { background: transparent; color: var(--fg-3, #8a978f); }
		.ms-row-ta { width: 100%; border: 1px solid var(--border, #e7e3d8); border-radius: 10px; padding: 9px 11px; font-size: 13px; line-height: 1.8; background: var(--surface, #fff); color: var(--fg-1, #16241d); font-family: inherit; resize: vertical; }
		.ms-row-ta:focus { outline: 2px solid var(--accent, #0f7a4a); outline-offset: 1px; }

		.ms-list-empty { display: flex; align-items: center; justify-content: center; gap: 8px; padding: 22px; border: 1.5px dashed var(--border-strong, #d6d1c0); border-radius: 12px; color: var(--fg-3, #8a978f); font-size: 12.5px; }
		.ms-list-foot { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
		.ms-btn { display: inline-flex; align-items: center; gap: 6px; border-radius: 10px; padding: 8px 14px; font-size: 12.5px; font-weight: 700; cursor: pointer; font-family: inherit; border: 1px solid var(--border-strong, #d6d1c0); background: var(--surface, #fff); color: var(--fg-1, #16241d); }
		.ms-btn .mi { font-size: 17px; }
		.ms-btn.primary { background: var(--accent, #0f7a4a); border-color: var(--accent, #0f7a4a); color: #fff; }
		.ms-btn.primary:hover { background: var(--accent-2, #0c6740); }
		.ms-btn[disabled] { opacity: .5; cursor: default; }
		.ms-list-hint { margin: 10px 0 0; font-size: 11.5px; color: var(--fg-3, #8a978f); line-height: 1.7; }
		</style>
		<script id="mersal-suite-fields-js">
		(function () {
			if (window.__mersalSuiteFields) return;
			window.__mersalSuiteFields = true;

			var LAST = null; // last textarea touched, so a chip knows where to insert

			function box(list) { return list.querySelector('[data-ms-rows-box]'); }
			function rows(list) { return Array.prototype.slice.call(list.querySelectorAll('[data-ms-row]')); }

			function label(list, i) {
				var tpl = list.getAttribute('data-ms-nth') || '';
				return tpl ? tpl.replace('%d', i + 1) : '';
			}

			function sync(list) {
				var rs = rows(list);
				var pinOffset = parseInt(list.getAttribute('data-ms-pin-offset') || '0', 10);

				rs.forEach(function (row, i) {
					var n = row.querySelector('[data-ms-n]');
					if (n) {
						// Keep whatever wording the server used for "Wording N";
						// only the number changes as rows move.
						n.textContent = n.textContent.replace(/\d+/, String(i + 1));
					}
					var pin = row.querySelector('[data-ms-pin-wrap] input');
					if (pin) pin.value = String(pinOffset + i);

					var up = row.querySelector('[data-ms-up]');
					var dn = row.querySelector('[data-ms-down]');
					if (up) up.disabled = (i === 0);
					if (dn) dn.disabled = (i === rs.length - 1);
				});

				var count = list.querySelector('[data-ms-count]');
				if (count) count.textContent = count.textContent.replace(/\d+/, String(rs.length));

				var empty = list.querySelector('[data-ms-empty]');
				if (empty) empty.hidden = rs.length > 0;

				var max = parseInt(list.getAttribute('data-ms-max') || '20', 10);
				var add = list.querySelector('[data-ms-add]');
				if (add) add.disabled = rs.length >= max;
			}

			function makeRow(list, value) {
				var tpl = rows(list)[0];
				var row;
				if (tpl) {
					row = tpl.cloneNode(true);
				} else {
					// The list was emptied, so there is no row to copy: rebuild the
					// minimum shape from what the container already knows.
					row = document.createElement('div');
					row.setAttribute('data-ms-row', '');
					row.className = 'ms-row';
					row.innerHTML =
						'<div class="ms-row-top"><span class="ms-row-n" data-ms-n>1</span>' +
						'<div class="ms-row-tools">' +
						'<button type="button" class="ms-icon" data-ms-up><span class="mi msym">arrow_upward</span></button>' +
						'<button type="button" class="ms-icon" data-ms-down><span class="mi msym">arrow_downward</span></button>' +
						'<button type="button" class="ms-icon danger" data-ms-del><span class="mi msym">delete</span></button>' +
						'</div></div>' +
						'<textarea class="ms-row-ta" rows="' + (list.getAttribute('data-ms-rows') || 3) + '" name="' +
						list.getAttribute('data-ms-name') + '[]"></textarea>';
				}
				var ta = row.querySelector('textarea');
				if (ta) ta.value = value || '';
				var pin = row.querySelector('[data-ms-pin-wrap] input');
				if (pin) pin.checked = false;
				return row;
			}

			document.addEventListener('click', function (e) {
				var t = e.target;

				var add = t.closest && t.closest('[data-ms-add]');
				if (add) {
					var l = add.closest('[data-ms-list]');
					var r = makeRow(l, '');
					box(l).appendChild(r);
					sync(l);
					var ta = r.querySelector('textarea');
					if (ta) ta.focus();
					return;
				}

				var del = t.closest && t.closest('[data-ms-del]');
				if (del) {
					var l2 = del.closest('[data-ms-list]');
					var row = del.closest('[data-ms-row]');
					if (row) row.remove();
					sync(l2);
					return;
				}

				var up = t.closest && t.closest('[data-ms-up]');
				if (up && !up.disabled) {
					var l3 = up.closest('[data-ms-list]');
					var r3 = up.closest('[data-ms-row]');
					if (r3 && r3.previousElementSibling) r3.parentNode.insertBefore(r3, r3.previousElementSibling);
					sync(l3);
					return;
				}

				var dn = t.closest && t.closest('[data-ms-down]');
				if (dn && !dn.disabled) {
					var l4 = dn.closest('[data-ms-list]');
					var r4 = dn.closest('[data-ms-row]');
					if (r4 && r4.nextElementSibling) r4.parentNode.insertBefore(r4.nextElementSibling, r4);
					sync(l4);
					return;
				}

				var rst = t.closest && t.closest('[data-ms-restore]');
				if (rst) {
					var l5 = rst.closest('[data-ms-list]');
					var defs = [];
					try { defs = JSON.parse(rst.getAttribute('data-ms-defaults') || '[]'); } catch (err) { defs = []; }
					if (!defs.length) return;
					if (!window.confirm(l5.getAttribute('data-ms-confirm') || 'Replace every wording with the ready-made set?')) return;
					var b = box(l5);
					// Build the new rows from a surviving template before emptying,
					// or cloneNode has nothing to copy the markup from.
					var built = defs.map(function (v) { return makeRow(l5, v); });
					b.innerHTML = '';
					built.forEach(function (r) { b.appendChild(r); });
					sync(l5);
					return;
				}

				var chip = t.closest && t.closest('[data-ms-chip]');
				if (chip) {
					var code = chip.getAttribute('data-ms-chip');
					var target = LAST && LAST.closest('[data-ms-list]') === chip.closest('[data-ms-list]')
						? LAST
						: chip.closest('[data-ms-list]').querySelector('textarea');
					if (!target) return;
					var start = target.selectionStart || 0;
					var end = target.selectionEnd || 0;
					target.value = target.value.slice(0, start) + code + target.value.slice(end);
					target.focus();
					target.selectionStart = target.selectionEnd = start + code.length;
					return;
				}
			});

			document.addEventListener('focusin', function (e) {
				if (e.target && e.target.matches && e.target.matches('.ms-row-ta')) LAST = e.target;
			});

			document.querySelectorAll('[data-ms-list]').forEach(sync);
		})();
		</script>
		<?php
	}
}
