/**
 * nterm zoom.js — UI scale, contrast mode, terminal font, and zoom controls.
 *
 * Works in two modes:
 *   1. Desktop (QWebEngineView) — zoom via setZoomFactor() from Python side,
 *      this module handles CSS --ui-scale, contrast class toggles, and terminal font.
 *   2. Browser-only — zoom via CSS --ui-scale on :root, stored in localStorage.
 *
 * Exposes:
 *   window.ntermZoom.setScale(factor)       — set CSS --ui-scale
 *   window.ntermZoom.getScale()             — current scale
 *   window.ntermZoom.zoomIn()               — increase by step
 *   window.ntermZoom.zoomOut()              — decrease by step
 *   window.ntermZoom.zoomReset()            — reset to 1.0
 *   window.ntermZoom.setContrast(mode)      — "normal" | "enhanced" | "high"
 *   window.ntermZoom.cycleContrast()        — cycle through modes
 *   window.ntermZoom.getContrast()          — current mode
 *   window.ntermZoom.setTerminalFont(size)  — set xterm.js font size (8–32)
 *   window.ntermZoom.termFontUp()           — increase terminal font
 *   window.ntermZoom.termFontDown()         — decrease terminal font
 *   window.ntermZoom.getTerminalFont()      — current terminal font size
 *   window.ntermZoom.applySettings(obj)     — bulk apply from desktop settings
 *
 * Terminal font bridge:
 *   window._setTerminalFontSize(size)       — called by desktop wrapper
 *   window._getTerminalFontSize()           — called by app.js on new Terminal()
 *
 * Status bar buttons are wired up automatically if the DOM elements exist.
 *
 * Keyboard shortcuts:
 *   Ctrl/Cmd + =/-/0         — UI scale (in/out/reset)
 *   Ctrl/Cmd + Alt + =/-/0   — Terminal font (up/down/reset)
 */

(function () {
  'use strict';

  const SCALE_MIN = 0.8;
  const SCALE_MAX = 1.5;
  const SCALE_STEP = 0.05;
  const TERM_FONT_MIN = 8;
  const TERM_FONT_MAX = 32;
  const TERM_FONT_STEP = 1;
  const TERM_FONT_DEFAULT = 14;
  const STORAGE_KEY_SCALE = 'nterm_ui_scale';
  const STORAGE_KEY_CONTRAST = 'nterm_contrast_mode';
  const STORAGE_KEY_TERM_FONT = 'nterm_terminal_font_size';

  let currentScale = 1.0;
  let currentContrast = 'normal';
  let currentTermFont = TERM_FONT_DEFAULT;

  // ── Persistence (browser-only; desktop uses settings.json) ──

  function loadFromStorage() {
    try {
      const s = localStorage.getItem(STORAGE_KEY_SCALE);
      if (s) currentScale = clampScale(parseFloat(s));
      const c = localStorage.getItem(STORAGE_KEY_CONTRAST);
      if (c && ['normal', 'enhanced', 'high'].includes(c)) currentContrast = c;
      const tf = localStorage.getItem(STORAGE_KEY_TERM_FONT);
      if (tf) currentTermFont = clampTermFont(parseInt(tf, 10));
    } catch {
      // localStorage might be blocked
    }
  }

  function saveToStorage() {
    try {
      localStorage.setItem(STORAGE_KEY_SCALE, currentScale.toFixed(2));
      localStorage.setItem(STORAGE_KEY_CONTRAST, currentContrast);
      localStorage.setItem(STORAGE_KEY_TERM_FONT, String(currentTermFont));
    } catch {
      // ignore
    }
  }

  // ── Helpers ──────────────────────────────────────────

  function clampScale(v) {
    return Math.round(Math.max(SCALE_MIN, Math.min(SCALE_MAX, v)) * 100) / 100;
  }

  function clampTermFont(v) {
    return Math.max(TERM_FONT_MIN, Math.min(TERM_FONT_MAX, v || TERM_FONT_DEFAULT));
  }

  function applyScale() {
    document.documentElement.style.setProperty('--ui-scale', currentScale);
    updateScaleIndicator();
  }

  function applyContrast() {
    const root = document.documentElement;
    root.classList.remove('contrast-enhanced', 'contrast-high');
    if (currentContrast === 'enhanced') root.classList.add('contrast-enhanced');
    if (currentContrast === 'high') root.classList.add('contrast-high');
    updateContrastButton();
  }

  /**
   * Apply terminal font size to ALL active xterm.js instances.
   * Accesses the global `state` object from app.js.
   */
  function applyTerminalFont() {
    if (typeof state === 'undefined' || !state.sessions) return;

    for (const [tabId, session] of Object.entries(state.sessions)) {
      if (session.term) {
        try {
          session.term.options.fontSize = currentTermFont;
          // Re-fit if fitAddon is available
          if (session.fitAddon) {
            session.fitAddon.fit();
          }
        } catch (e) {
          console.warn(`Failed to resize terminal ${tabId}:`, e);
        }
      }
    }
    updateTermFontIndicator();
  }

  function updateScaleIndicator() {
    const el = document.getElementById('zoom-indicator');
    if (el) {
      const pct = Math.round(currentScale * 100);
      el.textContent = pct === 100 ? '100%' : `${pct}%`;
      el.title = `UI Scale: ${pct}% (click to reset)`;
    }
  }

  function updateContrastButton() {
    const el = document.getElementById('contrast-toggle');
    if (el) {
      const labels = { normal: '◐ Normal', enhanced: '◑ Enhanced', high: '● High' };
      el.textContent = labels[currentContrast] || '◐ Normal';
      el.title = `Contrast: ${currentContrast} (click to cycle)`;
    }
  }

  function updateTermFontIndicator() {
    const el = document.getElementById('term-font-indicator');
    if (el) {
      el.textContent = `${currentTermFont}px`;
      el.title = `Terminal font: ${currentTermFont}px (click to reset to ${TERM_FONT_DEFAULT})`;
    }
  }

  // ── Public API ───────────────────────────────────────

  const api = {
    // ── UI Scale ───────────────────────────────────────
    setScale(factor) {
      currentScale = clampScale(factor);
      applyScale();
      saveToStorage();
      return currentScale;
    },

    getScale() {
      return currentScale;
    },

    zoomIn() {
      return api.setScale(currentScale + SCALE_STEP);
    },

    zoomOut() {
      return api.setScale(currentScale - SCALE_STEP);
    },

    zoomReset() {
      return api.setScale(1.0);
    },

    // ── Contrast ───────────────────────────────────────
    setContrast(mode) {
      if (['normal', 'enhanced', 'high'].includes(mode)) {
        currentContrast = mode;
        applyContrast();
        saveToStorage();
      }
      return currentContrast;
    },

    getContrast() {
      return currentContrast;
    },

    cycleContrast() {
      const modes = ['normal', 'enhanced', 'high'];
      const idx = modes.indexOf(currentContrast);
      return api.setContrast(modes[(idx + 1) % modes.length]);
    },

    // ── Terminal Font ──────────────────────────────────
    setTerminalFont(size) {
      currentTermFont = clampTermFont(size);
      applyTerminalFont();
      saveToStorage();
      return currentTermFont;
    },

    getTerminalFont() {
      return currentTermFont;
    },

    termFontUp() {
      return api.setTerminalFont(currentTermFont + TERM_FONT_STEP);
    },

    termFontDown() {
      return api.setTerminalFont(currentTermFont - TERM_FONT_STEP);
    },

    termFontReset() {
      return api.setTerminalFont(TERM_FONT_DEFAULT);
    },

    /**
     * Bulk apply settings from the desktop wrapper.
     * Called by nterm_desktop.py via page.runJavaScript().
     */
    applySettings(obj) {
      if (obj.ui_font_scale !== undefined) {
        currentScale = clampScale(obj.ui_font_scale);
        applyScale();
      }
      if (obj.contrast_mode !== undefined) {
        api.setContrast(obj.contrast_mode);
      }
      if (obj.terminal_font_size !== undefined) {
        currentTermFont = clampTermFont(obj.terminal_font_size);
        applyTerminalFont();
      }
    },

    /** Returns current state for desktop to persist */
    getState() {
      return {
        ui_font_scale: currentScale,
        contrast_mode: currentContrast,
        terminal_font_size: currentTermFont,
      };
    },
  };

  // ── Bridge functions for desktop wrapper / app.js ────
  window._setTerminalFontSize = function (size) {
    api.setTerminalFont(size);
  };

  /**
   * Called by app.js when creating a new Terminal().
   * Returns the user's preferred font size so new terminals
   * inherit the setting immediately.
   */
  window._getTerminalFontSize = function () {
    return currentTermFont;
  };

  // ── Init ─────────────────────────────────────────────

  loadFromStorage();

  function init() {
    applyScale();
    applyContrast();

    // Wire up status bar buttons
    const btnIn = document.getElementById('zoom-in');
    const btnOut = document.getElementById('zoom-out');
    const indicator = document.getElementById('zoom-indicator');
    const contrastBtn = document.getElementById('contrast-toggle');
    const termUp = document.getElementById('term-font-up');
    const termDown = document.getElementById('term-font-down');
    const termIndicator = document.getElementById('term-font-indicator');

    if (btnIn) btnIn.addEventListener('click', () => api.zoomIn());
    if (btnOut) btnOut.addEventListener('click', () => api.zoomOut());
    if (indicator) indicator.addEventListener('click', () => api.zoomReset());
    if (contrastBtn) contrastBtn.addEventListener('click', () => api.cycleContrast());
    if (termUp) termUp.addEventListener('click', () => api.termFontUp());
    if (termDown) termDown.addEventListener('click', () => api.termFontDown());
    if (termIndicator) termIndicator.addEventListener('click', () => api.termFontReset());

    updateTermFontIndicator();

    // Keyboard shortcuts
    document.addEventListener('keydown', (e) => {
      const mod = e.ctrlKey || e.metaKey;
      if (!mod) return;

      // ── UI Scale: Ctrl/Cmd + =/-/0 ──
      if (!e.shiftKey && !e.altKey) {
        if (e.key === '=' || e.key === '+') { e.preventDefault(); api.zoomIn(); }
        if (e.key === '-')                  { e.preventDefault(); api.zoomOut(); }
        if (e.key === '0')                  { e.preventDefault(); api.zoomReset(); }
      }

      // ── Terminal Font: Ctrl/Cmd + Alt + =/-/0 ──
      if (e.altKey && !e.shiftKey) {
        if (e.key === '=' || e.key === '+') { e.preventDefault(); api.termFontUp(); }
        if (e.key === '-')                  { e.preventDefault(); api.termFontDown(); }
        if (e.key === '0')                  { e.preventDefault(); api.termFontReset(); }
      }
    });
  }

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

  window.ntermZoom = api;
})();