import $ from 'jquery';
import { ajax, localStorage as ls } from 'peepso';

// Config injected via wp_localize_script (PeepSoEmoji::enqueue_scripts).
const cfg = window.peepsoemojidata || {};
const REST = cfg.rest || '';
// set/groups are stable per version+locale, so they can be cached across page loads; quick is per-user.
const LS_KEY = `emoji_${cfg.version || '0'}_${cfg.locale || 'en'}`;

let payload = null; // resolved { set, groups, search, quick } for this page
let loading = null; // in-flight Deferred shared by concurrent openers

function readLS() {
	try {
		const raw = ls.get(LS_KEY);
		if (!raw) return null;
		const data = JSON.parse(raw);
		return data && data.set ? data : null;
	} catch (e) {
		return null;
	}
}

function writeLS(data) {
	try {
		ls.set(LS_KEY, JSON.stringify({ set: data.set, groups: data.groups, search: data.search }));
	} catch (e) {}
}

const data = {
	/**
	 * Resolve the picker payload, fetching at most once per page. When set/groups are already cached in
	 * localStorage, only the per-user quick shelf is re-fetched.
	 */
	load() {
		if (payload) return $.Deferred().resolve(payload);
		if (loading) return loading;

		loading = $.Deferred();

		const cached = readLS();
		if (cached) {
			ajax.get(REST, { quick: 1 })
				.done(json => {
					payload = $.extend({}, cached, { quick: (json && json.quick) || [] });
					loading.resolve(payload);
				})
				.fail(() => {
					payload = $.extend({}, cached, { quick: [] });
					loading.resolve(payload);
				});
		} else {
			ajax.get(REST)
				.done(json => {
					if (json && json.set) {
						writeLS(json);
						payload = json;
						loading.resolve(payload);
					} else {
						loading.reject();
						loading = null;
					}
				})
				.fail(() => {
					loading.reject();
					loading = null;
				});
		}

		return loading;
	},

	/** Record one use of a glyph for the current user; keeps the cached quick shelf fresh so a re-opened
	 *  picker reflects favorites added this session, and resolves with the server's refreshed shelf. */
	bump(glyph) {
		if (payload) {
			payload.quick = [glyph].concat((payload.quick || []).filter(g => g !== glyph)).slice(0, 6);
		}
		return ajax.post(REST, { glyph }).done(json => {
			if (payload && json && json.quick) payload.quick = json.quick;
		});
	},

	/** Insert a glyph at the caret of a textarea (or a contenteditable fallback) and fire `input`. */
	insertAtCursor($ta, glyph) {
		const el = $ta && $ta.get ? $ta.get(0) : $ta;
		if (!el) return;

		el.focus();

		if (typeof el.selectionStart === 'number' && typeof el.value === 'string') {
			const s = el.selectionStart;
			const e = el.selectionEnd;
			el.value = el.value.slice(0, s) + glyph + el.value.slice(e);
			el.selectionStart = el.selectionEnd = s + glyph.length;
		} else if (document.execCommand) {
			// contenteditable surfaces (e.g. background posts) have no selectionStart.
			document.execCommand('insertText', false, glyph);
		}

		// Native event so both jQuery-bound (postbox) and inline oninput (comments) handlers fire —
		// re-enables the submit button, autosize and char count.
		el.dispatchEvent(new Event('input', { bubbles: true }));
	}
};

export default data;
