/* global window, localStorage, sessionStorage */
window.Niwa = window.Niwa || {};

window.Niwa.AdminChatPersistence = (function () {
  'use strict';

  var PENDING_KEY = 'niwa_admin_chat_pending';
  var LOCAL_MESSAGES_KEY = 'niwa_admin_chat_local_messages';
	var SEND_QUEUE_KEY = 'niwa_admin_chat_send_queue';
  var SESSION_MARKER_KEY = 'niwa_admin_chat_wp_session';
	var PENDING_TTL_MS = 24 * 60 * 60 * 1000;
	var currentSessionKey = '';
  var LOCAL_MESSAGES_TTL_MS = 30 * 60 * 1000;
  var LEGACY_CLEANUP_KEY = 'niwa_admin_chat_cleaned_v1';
	var REQUEST_ID_MIGRATION_KEY = 'niwa_admin_chat_request_ids_v1';
  var OLD_ADMIN_KEYS = [
    'niwa_ai_admin_autonomy_history_v1',
    'niwa_ai_admin_autonomy_history_v1_gv',
    'niwa_ai_admin_autonomy_history_v1_last_seen_bot',
    'niwa_ai_admin_autonomy_history_v1_pending_reply'
  ];

  function cleanupLegacyStorage() {
    try {
	  if (sessionStorage.getItem(REQUEST_ID_MIGRATION_KEY) !== '1') {
		sessionStorage.removeItem(LOCAL_MESSAGES_KEY);
		sessionStorage.setItem(REQUEST_ID_MIGRATION_KEY, '1');
	  }
      if (localStorage.getItem(LEGACY_CLEANUP_KEY) === '1') return;
      for (var i = 0; i < OLD_ADMIN_KEYS.length; i++) {
        localStorage.removeItem(OLD_ADMIN_KEYS[i]);
        sessionStorage.removeItem(OLD_ADMIN_KEYS[i]);
      }
      localStorage.setItem(LEGACY_CLEANUP_KEY, '1');
    } catch (e) { /* ignore */ }
  }

  function resetForSession(sessionKey) {
    if (!sessionKey) return;
    try {
      var key = String(sessionKey);
	  currentSessionKey = key;
      if (sessionStorage.getItem(SESSION_MARKER_KEY) === key) return;
	  var legacyPending = sessionStorage.getItem(PENDING_KEY);
	  if (legacyPending && !localStorage.getItem(scopedPendingKey())) localStorage.setItem(scopedPendingKey(), legacyPending);
	  sessionStorage.removeItem(PENDING_KEY);
      sessionStorage.removeItem(LOCAL_MESSAGES_KEY);
	  sessionStorage.removeItem(SEND_QUEUE_KEY);
      sessionStorage.setItem(SESSION_MARKER_KEY, key);
    } catch (e) { /* ignore */ }
  }

  function savePending(pending) {
    try {
	  var list = Array.isArray(pending) ? pending : (pending ? [pending] : []);
	  for (var i = 0; i < list.length; i++) writePendingJob(list[i]);
    } catch (e) { /* ignore */ }
  }

  function loadPending() {
    try {
	  migratePendingLedger();
	  var jobs = [];
	  var cutoff = Date.now() - PENDING_TTL_MS;
	  for (var i = localStorage.length - 1; i >= 0; i--) {
		var key = localStorage.key(i);
		if (!key) continue;
		if (key.indexOf(scopedPendingPrefix() + 'done_') === 0) {
		  if (parseInt(localStorage.getItem(key) || 0, 10) < cutoff) localStorage.removeItem(key);
		  continue;
		}
		if (key.indexOf(scopedPendingPrefix() + 'job_') !== 0) continue;
		var job = JSON.parse(localStorage.getItem(key));
		if (!job || !job.sentAt || job.sentAt < cutoff || isPendingJobTombstoned(job)) localStorage.removeItem(key);
		else jobs.push(job);
	  }
	  return jobs.sort(function (a, b) { return a.sentAt - b.sentAt; }).slice(-50);
    } catch (e) {
      return null;
    }
  }

  function clearPending() {
    try {
      sessionStorage.removeItem(PENDING_KEY);
	  localStorage.removeItem(scopedPendingKey());
	  for (var i = localStorage.length - 1; i >= 0; i--) {
		var key = localStorage.key(i);
		if (key && key.indexOf(scopedPendingPrefix()) === 0) localStorage.removeItem(key);
	  }
    } catch (e) { /* ignore */ }
  }

	function removePending(identity, remaining) {
	  try {
		var jobs = loadPending();
		var removed = jobs.filter(function (job) { return matchesPendingIdentity(job, identity); });
		var now = Date.now();
		var keys = [String(identity || '')];
		for (var i = 0; i < removed.length; i++) keys = keys.concat(pendingIdentityKeys(removed[i]));
		for (var j = 0; j < keys.length; j++) if (keys[j]) localStorage.setItem(pendingTombstoneKey(keys[j]), String(now));
		for (var k = 0; k < removed.length; k++) localStorage.removeItem(pendingJobKey(removed[k]));
		savePending(Array.isArray(remaining) ? remaining : []);
	  } catch (e) { /* ignore */ }
	}

	function writePendingJob(job) {
	  if (!job || !job.sentAt || !pendingIdentityKeys(job).length) return;
	  var savedAt = parseInt(job._savedAt || job.sentAt, 10) || Date.now();
	  job = Object.assign({}, job, { _savedAt: savedAt });
	  if (isPendingJobTombstoned(job)) return;
	  var key = pendingJobKey(job);
	  localStorage.setItem(key, JSON.stringify(job));
	  if (isPendingJobTombstoned(job)) localStorage.removeItem(key);
	}

	function migratePendingLedger() {
	  var raw = localStorage.getItem(scopedPendingKey()) || sessionStorage.getItem(PENDING_KEY);
	  if (!raw) return;
	  localStorage.removeItem(scopedPendingKey());
	  sessionStorage.removeItem(PENDING_KEY);
	  var parsed = JSON.parse(raw);
	  var jobs = Array.isArray(parsed) ? parsed : (parsed && Array.isArray(parsed.jobs) ? parsed.jobs : (parsed && parsed.sentAt ? [parsed] : []));
	  savePending(jobs);
	}

	function isPendingJobTombstoned(job) {
	  var savedAt = parseInt(job._savedAt || job.sentAt, 10) || 0;
	  return pendingIdentityKeys(job).some(function (identity) {
		return parseInt(localStorage.getItem(pendingTombstoneKey(identity)) || 0, 10) >= savedAt;
	  });
	}

	function pendingIdentityKeys(job) {
	  var keys = [];
	  if (job && job.jobId) keys.push(String(job.jobId));
	  if (job && job.requestId) keys.push(String(job.requestId));
	  return keys;
	}

	function scopedPendingPrefix() {
	  return scopedPendingKey() + '_';
	}

	function pendingJobKey(job) {
	  return scopedPendingPrefix() + 'job_' + simpleHash(job.requestId || job.jobId);
	}

	function pendingTombstoneKey(identity) {
	  return scopedPendingPrefix() + 'done_' + simpleHash(identity);
	}

	function matchesPendingIdentity(job, identity) {
	  identity = String(identity || '');
	  return !!identity && !!job && (job.jobId === identity || job.requestId === identity);
	}

	function scopedPendingKey() {
	  return PENDING_KEY + '_' + simpleHash(currentSessionKey || 'anonymous');
	}

	function onPendingChange(callback) {
	  if (typeof callback !== 'function') return;
	  window.addEventListener('storage', function (event) {
		if (!event.key || (event.key !== scopedPendingKey() && event.key.indexOf(scopedPendingPrefix()) !== 0)) return;
		callback(loadPending());
	  });
	}

	function simpleHash(value) {
	  var hash = 0;
	  value = String(value || '');
	  for (var i = 0; i < value.length; i++) hash = ((hash << 5) - hash + value.charCodeAt(i)) | 0;
	  return Math.abs(hash).toString(36);
	}

  function loadLocalMessages() {
    try {
      var raw = sessionStorage.getItem(LOCAL_MESSAGES_KEY);
      if (!raw) return [];
      var parsed = JSON.parse(raw);
      if (!Array.isArray(parsed)) return [];

      var cutoff = Date.now() - LOCAL_MESSAGES_TTL_MS;
      var out = [];
      for (var i = 0; i < parsed.length; i++) {
        var msg = parsed[i];
        if (!msg || !msg.ts || (msg.ts * 1000) < cutoff) continue;
        out.push(msg);
      }
      return out;
    } catch (e) {
      return [];
    }
  }

  function writeLocalMessages(messages) {
    var list = Array.isArray(messages) ? messages : [];
    try {
      if (!list.length) {
        sessionStorage.removeItem(LOCAL_MESSAGES_KEY);
        return;
      }
      sessionStorage.setItem(LOCAL_MESSAGES_KEY, JSON.stringify(list.slice(-20)));
    } catch (e) { /* ignore */ }
  }

	function loadSendQueue() {
		try {
			var raw = sessionStorage.getItem(SEND_QUEUE_KEY);
			var list = raw ? JSON.parse(raw) : [];
			if (!Array.isArray(list)) return [];
			var cutoff = Date.now() - PENDING_TTL_MS;
			return list.filter(function (item) { return item && item.text && item.sentAt >= cutoff; }).slice(-50);
		} catch (e) {
			return [];
		}
	}

	function writeSendQueue(items) {
		try {
			var list = Array.isArray(items) ? items.slice(-50) : [];
			if (!list.length) {
				sessionStorage.removeItem(SEND_QUEUE_KEY);
				return;
			}
			sessionStorage.setItem(SEND_QUEUE_KEY, JSON.stringify(list));
		} catch (e) { /* ignore */ }
	}

  return {
    cleanupLegacyStorage: cleanupLegacyStorage,
    resetForSession: resetForSession,
    savePending: savePending,
    loadPending: loadPending,
    clearPending: clearPending,
	removePending: removePending,
    loadLocalMessages: loadLocalMessages,
	writeLocalMessages: writeLocalMessages,
	loadSendQueue: loadSendQueue,
	writeSendQueue: writeSendQueue,
	onPendingChange: onPendingChange
  };
})();
