/**
 * Zeq CKO Client — Compiled Kinematic Output handler for Chrome Extension
 * Parses, caches, and distributes CKO waveform data from API responses.
 *
 * @version 1.287.3
 * @license CC BY 4.0 — Zeq. H / Zeq 1.287 Hz Limited
 */

const CKOClient = (() => {
  'use strict';

  // ── Constants ──────────────────────────────────────────────────────────
  const CACHE_KEY    = 'zeq_cko_latest';
  const HISTORY_KEY  = 'zeq_cko_history';
  const MAX_HISTORY  = 50;

  // ── State ──────────────────────────────────────────────────────────────
  let _latestCKO   = null;
  let _listeners   = [];

  // ── Parse CKO from non-streaming API response ─────────────────────────
  function parseFromResponse(responseJSON) {
    if (!responseJSON) return null;

    try {
      const data = typeof responseJSON === 'string'
        ? JSON.parse(responseJSON)
        : responseJSON;

      if (data.waveformOutput && data.waveformOutput.cko) {
        const ckoData = {
          cko:             data.waveformOutput.cko,
          computationTime: data.waveformOutput.computationTime || 0,
          metadata:        data.zeqMetadata || null,
          timestamp:       Date.now(),
          source:          'non-streaming',
        };
        _setCKO(ckoData);
        return ckoData;
      }
    } catch (e) {
      console.warn('[CKO Client] Parse error:', e.message);
    }
    return null;
  }

  // ── Parse CKO from SSE streaming event ────────────────────────────────
  function parseFromSSE(eventData) {
    try {
      const parsed = typeof eventData === 'string'
        ? JSON.parse(eventData)
        : eventData;

      if (parsed.type === 'zeq_cko' && parsed.cko) {
        const ckoData = {
          cko:             parsed.cko,
          computationTime: parsed.metadata?.computationTime || 0,
          metadata:        parsed.metadata || null,
          timestamp:       Date.now(),
          source:          'streaming',
        };
        _setCKO(ckoData);
        return ckoData;
      }
    } catch (e) {
      console.warn('[CKO Client] SSE parse error:', e.message);
    }
    return null;
  }

  // ── Internal: set CKO and notify ──────────────────────────────────────
  function _setCKO(ckoData) {
    _latestCKO = ckoData;

    // Persist to chrome.storage.session for cross-context access
    if (typeof chrome !== 'undefined' && chrome.storage?.session) {
      chrome.storage.session.set({ [CACHE_KEY]: ckoData }).catch(() => {});

      // Append to history
      chrome.storage.session.get(HISTORY_KEY, (result) => {
        const history = result[HISTORY_KEY] || [];
        history.unshift({
          timestamp:       ckoData.timestamp,
          domain:          ckoData.cko?.metadata?.primaryDomain || 'unknown',
          stability:       ckoData.cko?.stability?.index ?? null,
          computationTime: ckoData.computationTime,
        });
        if (history.length > MAX_HISTORY) history.length = MAX_HISTORY;
        chrome.storage.session.set({ [HISTORY_KEY]: history }).catch(() => {});
      });
    }

    // Notify listeners
    _listeners.forEach(fn => {
      try { fn(ckoData); } catch (e) { console.warn('[CKO Client] Listener error:', e); }
    });

    // Broadcast to extension contexts
    if (typeof chrome !== 'undefined' && chrome.runtime?.sendMessage) {
      chrome.runtime.sendMessage({
        type:    'zeq_cko_update',
        payload: ckoData,
      }).catch(() => {}); // Ignore if no receivers
    }
  }

  // ── Get latest CKO ────────────────────────────────────────────────────
  function getLatest() {
    return _latestCKO;
  }

  // ── Get from storage (async) ──────────────────────────────────────────
  async function getFromStorage() {
    if (typeof chrome !== 'undefined' && chrome.storage?.session) {
      return new Promise((resolve) => {
        chrome.storage.session.get(CACHE_KEY, (result) => {
          resolve(result[CACHE_KEY] || null);
        });
      });
    }
    return _latestCKO;
  }

  // ── Get history ───────────────────────────────────────────────────────
  async function getHistory() {
    if (typeof chrome !== 'undefined' && chrome.storage?.session) {
      return new Promise((resolve) => {
        chrome.storage.session.get(HISTORY_KEY, (result) => {
          resolve(result[HISTORY_KEY] || []);
        });
      });
    }
    return [];
  }

  // ── Subscribe to CKO updates ──────────────────────────────────────────
  function onUpdate(callback) {
    if (typeof callback === 'function') {
      _listeners.push(callback);
    }
    return () => {
      _listeners = _listeners.filter(fn => fn !== callback);
    };
  }

  // ── Extract key metrics for display ───────────────────────────────────
  function extractMetrics(ckoData) {
    if (!ckoData?.cko) return null;
    const c = ckoData.cko;
    return {
      stabilityIndex:     c.stability?.index ?? 0,
      phaseLock:          c.stability?.phaseLock ?? 0,
      energyDrift:        c.stability?.energyDriftPercent ?? 0,
      waveformStable:     c.stability?.waveformStable ?? false,
      goldenRatio:        c.agoHarmonics?.goldenRatioVerified ?? false,
      ko42Compliant:      c.ko42?.compliant ?? false,
      primaryDomain:      c.metadata?.primaryDomain || 'unknown',
      operatorsUsed:      c.metadata?.operatorsUsed || [],
      confidenceScore:    c.metadata?.confidenceScore ?? 0,
      spectralPeaks:      c.spectral?.peaks || [],
      interpretation:     c.interpretation || '',
      computationTime:    ckoData.computationTime || 0,
      parameters:         c.parameters || {},
    };
  }

  // ── Synthesize display waveform from spectral peaks ───────────────────
  function synthesizeWaveform(spectralPeaks, numPoints = 200) {
    if (!spectralPeaks || spectralPeaks.length === 0) {
      return { timestamps: [], amplitudes: [] };
    }

    const duration   = 1.554; // 2 Zeqonds
    const dt         = duration / numPoints;
    const timestamps = [];
    const amplitudes = [];

    for (let i = 0; i < numPoints; i++) {
      const t   = i * dt;
      let value = 0;
      for (const peak of spectralPeaks) {
        const freq = peak.frequency || peak.freq || 0;
        const amp  = peak.amplitude || peak.amp || 0;
        const phi  = peak.phase || 0;
        value += amp * Math.sin(2 * Math.PI * freq * t + phi);
      }
      timestamps.push(t);
      amplitudes.push(value);
    }

    return { timestamps, amplitudes };
  }

  // ── Stability grade ───────────────────────────────────────────────────
  function stabilityGrade(index) {
    if (index >= 0.95) return { label: 'EXCELLENT', color: '#22c55e' };
    if (index >= 0.80) return { label: 'GOOD',      color: '#84cc16' };
    if (index >= 0.60) return { label: 'MODERATE',   color: '#eab308' };
    if (index >= 0.40) return { label: 'FAIR',       color: '#f97316' };
    return                     { label: 'UNSTABLE',   color: '#ef4444' };
  }

  // ── Listen for CKO broadcasts from other contexts ─────────────────────
  if (typeof chrome !== 'undefined' && chrome.runtime?.onMessage) {
    chrome.runtime.onMessage.addListener((message) => {
      if (message.type === 'zeq_cko_update' && message.payload) {
        _latestCKO = message.payload;
        _listeners.forEach(fn => {
          try { fn(message.payload); } catch (e) { /* noop */ }
        });
      }
    });
  }

  // ── Public API ─────────────────────────────────────────────────────────
  return {
    parseFromResponse,
    parseFromSSE,
    getLatest,
    getFromStorage,
    getHistory,
    onUpdate,
    extractMetrics,
    synthesizeWaveform,
    stabilityGrade,
  };
})();

// Export for both module and script contexts
if (typeof module !== 'undefined' && module.exports) {
  module.exports = CKOClient;
}
