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

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

  var store = null;
  var view = null;
  var textarea = null;
  var sendBtn = null;
  var transport = null;
  var history = null;
  var status = null;
  var poller = null;
  var queue = null;
  var initialized = false;
  var initializing = false;
  var initialLoaded = false;
  var loadingInitial = false;
  var loadingOlder = false;
  var statusRestoreInFlight = null;
  var unreadCount = 0;
  var supportModulesReady = null;
  var clientScriptUrl = resolveClientScriptUrl();
  var INITIAL_HISTORY_LIMIT = 30;
  var FRESH_ADMIN_SESSION = true;
  var SUPPORT_MODULES = [
    { globalName: 'AdminChatTransport', fileName: 'admin-chat-transport.js' },
    { globalName: 'AdminChatHistory', fileName: 'admin-chat-history.js' },
    { globalName: 'AdminChatStatus', fileName: 'admin-chat-status.js' },
    { globalName: 'AdminChatPersistence', fileName: 'admin-chat-persistence.js' },
    { globalName: 'AdminChatPoller', fileName: 'admin-chat-poller.js' },
    { globalName: 'AdminChatQueue', fileName: 'admin-chat-queue.js' }
  ];

  function init() {
    if (initialized || initializing) return;
    if (!(window.NiwaAI && window.NiwaAI.admin_mode)) return;

    initializing = true;
    ensureSupportModules().then(initReady).catch(function (error) {
      initializing = false;
      if (window.console && window.console.error) {
        window.console.error('[Niwa AI] Admin chat support modules failed to load.', error);
      }
    });
  }

  function initReady() {
    if (initialized) return;
    initialized = true;
    initializing = false;

    var bodyEl = document.querySelector('.niwa-morph__body[data-niwa-admin-chat="1"]')
      || document.querySelector('.niwa-morph__body');
    if (!bodyEl) return;

    if (window.Niwa.AdminChatPersistence) {
      window.Niwa.AdminChatPersistence.cleanupLegacyStorage();
      window.Niwa.AdminChatPersistence.resetForSession((window.NiwaAI && window.NiwaAI.admin_session_key) || '');
    }
    FRESH_ADMIN_SESSION = !(window.NiwaAI && window.NiwaAI.admin_fresh_session === false);

    if (window.Niwa.ThemeSwitcher) {
      window.Niwa.ThemeSwitcher.init();
    }

    initMorph();
    store = window.Niwa.AdminChatStore;
    view = window.Niwa.AdminChatView;
    if (!store || !view) return;

    transport = window.Niwa.AdminChatTransport.create();
    history = window.Niwa.AdminChatHistory.create({ transport: transport, defaultLimit: INITIAL_HISTORY_LIMIT });
    status = window.Niwa.AdminChatStatus.create({ transport: transport });
    queue = window.Niwa.AdminChatQueue.create({
      store: store,
      transport: transport,
      setInputValue: setInputValue,
      syncSendDisabled: syncSendDisabled,
      onTailNeeded: scheduleTailPoll,
      onIdleNeeded: startIdleTailPoll,
      onAjaxError: handleAjaxError
    });
    poller = window.Niwa.AdminChatPoller.create({
      store: store,
      history: history,
      status: status,
      limit: INITIAL_HISTORY_LIMIT,
	  onBotTail: function () {}
    });
	store.on('pending:set', function () {
	  if (store.getState().isOpen) scheduleTailPoll(0);
	});

    view.init(bodyEl, store, { onLoadOlder: loadOlder });
    bindUnreadBadge();
    bindSendHandlers();
    bindLifecycle();

    store.loadPending();
    if (store.getState().pending) {
      loadInitial().then(function () {
        refreshPendingRender();
        scheduleTailPoll(0);
      });
    } else {
      restoreActiveServerTurn();
    }

    window.niwaAI = window.niwaAI || {};
    window.niwaAI.openChat = function () {
      if (window.Niwa.MorphController) window.Niwa.MorphController.open();
    };
    window.niwaAI.sendMessage = sendMessage;
  }

  function initMorph() {
    var cfg = window.NiwaAI || {};
    var desktopPos = (cfg.launcher_desktop && cfg.launcher_desktop.position) || 'br';
    if (window.Niwa.MorphController) {
      window.Niwa.MorphController.init({
        mode: 'morph',
        position: desktopPos,
        admin_mode: true,
        launcher_text: cfg.launcher_text || '',
        assistant_display_name: cfg.assistant_display_name || '',
        launcher_desktop: cfg.launcher_desktop || { position: 'br' },
        launcher_tablet: cfg.launcher_tablet || { position: 'br' },
        launcher_mobile: cfg.launcher_mobile || { position: 'br' }
      });
      textarea = window.Niwa.MorphController.getTextarea();
      sendBtn = window.Niwa.MorphController.getSendBtn();
    }
  }

  function bindLifecycle() {
    window.addEventListener('niwa:morph:open', function () {
      store.setOpen(true);
      clearUnreadBadge();
      if (!FRESH_ADMIN_SESSION && !initialLoaded && !loadingInitial) {
        loadInitial().then(function () {
          restoreActiveServerTurn();
        });
      } else if (!store.getState().pending) {
        restoreActiveServerTurn();
      }
      startIdleTailPoll();
      if (store.getState().pending) {
        refreshPendingRender();
        scheduleTailPoll(0);
      }
    });

    window.addEventListener('niwa:morph:close', function () {
      store.setOpen(false);
      stopIdleTailPoll();
      if (!store.getState().pending) {
        stopTailPoll();
      }
    });

    document.addEventListener('visibilitychange', function () {
      if (document.hidden) {
        stopTailPoll();
        stopIdleTailPoll();
        return;
      }

      var state = store.getState();
      if (!state.isOpen && !state.pending) return;
      if (state.isOpen) startIdleTailPoll();
      if (state.pending) {
        scheduleTailPoll(0);
      } else if (state.isOpen) {
        pollTail();
      }
    });
  }

  function bindSendHandlers() {
    function run() {
      if (!textarea) return;
      sendMessage(textarea.value || '');
    }

    if (textarea) {
      textarea.addEventListener('keydown', function (event) {
        if (event.key === 'Enter' && !event.shiftKey) {
          event.preventDefault();
          run();
        }
      });
      textarea.addEventListener('input', syncSendDisabled);
    }

    if (sendBtn) {
      sendBtn.addEventListener('click', run);
    }
  }

  function bindUnreadBadge() {
    if (!store) return;

    store.on('messages:appended', function (payload) {
      var message = payload && payload.message ? payload.message : null;
      if (!message || message.role === 'user') return;

      var state = store.getState();
      if (state.isOpen) return;

      unreadCount += 1;
      if (window.Niwa && window.Niwa.MorphController && typeof window.Niwa.MorphController.showBadge === 'function') {
        window.Niwa.MorphController.showBadge(unreadCount);
      }
    });
  }

  function clearUnreadBadge() {
    unreadCount = 0;
    if (window.Niwa && window.Niwa.MorphController && typeof window.Niwa.MorphController.clearBadge === 'function') {
      window.Niwa.MorphController.clearBadge();
    }
  }

  function sendMessage(rawText) {
    if (queue) {
      queue.sendMessage(rawText);
    }
  }

  function loadInitial() {
    if (!history || !store || loadingInitial) return Promise.resolve();
    loadingInitial = true;
    return history.requestHistory({ mode: 'initial', limit: INITIAL_HISTORY_LIMIT }).then(function (payload) {
      initialLoaded = true;
      store.replace(payload.history || [], payload);
      if (store.getState().pending) {
        refreshPendingRender();
        scheduleTailPoll(0);
      }
    }).catch(function () {
      initialLoaded = false;
    }).then(function () {
      loadingInitial = false;
    });
  }

  function loadOlder() {
    if (loadingOlder || !store || !history) return;
    var state = store.getState();
    if (!state.hasMore || (!state.oldestId && !state.oldestTs)) return;

    loadingOlder = true;
    history.requestHistory({ mode: 'older', limit: INITIAL_HISTORY_LIMIT, before_id: state.oldestId, before_ts: state.oldestTs }).then(function (payload) {
      store.prepend(payload.history || [], payload);
    }).then(function () {
      loadingOlder = false;
    }).catch(function () {
      loadingOlder = false;
    });
  }

  function restoreActiveServerTurn() {
    if (!status || !store) return Promise.resolve();
    if (statusRestoreInFlight) return statusRestoreInFlight;

    statusRestoreInFlight = status.requestStatus('').then(function (payload) {
      if (!payload || !(payload.status === 'pending' || payload.status === 'processing') || !payload.jobId) return;
      store.setPending(payload.message || '', payload.createdAt ? payload.createdAt * 1000 : Date.now(), {
        jobId: payload.jobId,
        requestId: payload.requestId || '',
        session: payload.session || '',
        generation: payload.generation || 0
      });
      refreshPendingRender();
      scheduleTailPoll(0);
    }).catch(function () {}).then(function () {
      statusRestoreInFlight = null;
    });

    return statusRestoreInFlight;
  }

  function refreshPendingRender() {
    if (store && typeof store.refreshPending === 'function') {
      store.refreshPending();
    }
    if (view && typeof view.renderPendingIfNeeded === 'function') {
      view.renderPendingIfNeeded();
    }
  }

  function pollTail() {
    return poller ? poller.pollTail() : Promise.resolve();
  }

  function scheduleTailPoll(delay) {
    if (poller) poller.scheduleTailPoll(delay);
  }

  function stopTailPoll() {
    if (poller) poller.stopTailPoll();
  }

  function startIdleTailPoll() {
    if (poller) poller.startIdleTailPoll();
  }

  function stopIdleTailPoll() {
    if (poller) poller.stopIdleTailPoll();
  }

  function handleAjaxError(response, fallback) {
    var message = fallback;
    if (window.Niwa && window.Niwa.Utils && window.Niwa.Utils.extractAjaxErrorMessage) {
      message = window.Niwa.Utils.extractAjaxErrorMessage(response, fallback);
    }
    store.append({ role: 'bot', text: message, ts: Math.floor(Date.now() / 1000), source: 'admin_error' });
  }

  function setInputValue(value) {
    if (!textarea) return;
    textarea.value = value;
    if (window.Niwa.MorphController && window.Niwa.MorphController.syncTextareaLayout) {
      window.Niwa.MorphController.syncTextareaLayout();
    }
  }

  function syncSendDisabled() {
    if (!sendBtn) return;
    sendBtn.classList.toggle('niwa-morph__send--disabled', !(textarea && textarea.value.trim()));
  }

  function ensureSupportModules() {
    if (supportModulesReady) return supportModulesReady;
    if (hasSupportModules()) {
      supportModulesReady = Promise.resolve();
      return supportModulesReady;
    }

    supportModulesReady = SUPPORT_MODULES.reduce(function (promise, item) {
      return promise.then(function () {
        if (window.Niwa && window.Niwa[item.globalName]) return Promise.resolve();
        return loadScript(buildSupportModuleUrl(item.fileName));
      });
    }, Promise.resolve());

    return supportModulesReady;
  }

  function hasSupportModules() {
    for (var i = 0; i < SUPPORT_MODULES.length; i++) {
      if (!(window.Niwa && window.Niwa[SUPPORT_MODULES[i].globalName])) return false;
    }
    return true;
  }

  function loadScript(src) {
    return new Promise(function (resolve, reject) {
      if (!src) {
        reject(new Error('missing_support_module_url'));
        return;
      }

      var script = document.createElement('script');
      script.src = src;
      script.async = false;
      script.onload = resolve;
      script.onerror = function () {
        reject(new Error('failed_to_load_' + src));
      };
      document.head.appendChild(script);
    });
  }

  function buildSupportModuleUrl(fileName) {
    if (!clientScriptUrl) return fileName;
    return clientScriptUrl.replace(/admin-chat-client\.js(\?.*)?$/, fileName + '$1');
  }

  function resolveClientScriptUrl() {
    var current = document.currentScript;
    if (current && current.src && current.src.indexOf('admin-chat-client.js') !== -1) {
      return current.src;
    }

    var scripts = document.getElementsByTagName('script');
    for (var i = scripts.length - 1; i >= 0; i--) {
      if (scripts[i].src && scripts[i].src.indexOf('admin-chat-client.js') !== -1) {
        return scripts[i].src;
      }
    }
    return '';
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }

  return {
    init: init,
    sendMessage: sendMessage,
    loadInitial: loadInitial,
    loadOlder: loadOlder,
    pollTail: pollTail
  };
})();
