/**
 * NS Analytics アダプタ — `neccospeak/v1/events` へのバッチ送信 (計画書 §1.2.3 / §3.2(5))。
 *
 * `widget/analytics-tracker.js` の `AnalyticsTracker` と同じメソッド名の
 * ファサードを提供する（呼び出し元 `widget-app-persistent.js` は無改変）。
 *
 * pocxr 本番の `widget-analytics` (session/messages/events の3種+beacon) は
 * 全て削除し、このアダプタは唯一残る `POST {restUrl}events` のみを扱う
 * (§3.2(5) の「流用(最小)」対象1件のみ)。`features.analytics.enabled` が
 * true のときのみ送信し、最大20件/8KBのバッチで `{sid, events:[{n:"..."}]}`
 * 形状にして送る。イベント名はサーバー側 allow-list に intersect される
 * ため、pocxr 独自のイベント名 (navigate/mode_switch/quick_action/error) は
 * サーバーに捨てられる想定でそのまま転送する。
 */

import { nsFetch } from "./ns-rest.js";

const MAX_BATCH = 20;
const MAX_BYTES = 8000;
const FLUSH_INTERVAL_MS = 15000;

function analyticsEnabled() {
  const cfg = (typeof window !== "undefined" && window.__AGENT_CONFIG__) || {};
  return !!(cfg.analytics && cfg.analytics.enabled);
}

function restEventsUrl() {
  const base = (typeof window !== "undefined" && window.__NS_REST__) || "/wp-json/neccospeak/v1/";
  return `${base.endsWith("/") ? base : `${base}/`}events`;
}

export class NsAnalytics {
  constructor() {
    this.sid = null;
    this._buffer = [];
    this._flushTimer = null;
    this._setupBeaconListeners();
  }

  // ============================================
  // セッション管理 (NS には session 概念が無いため sid の保持のみ)
  // ============================================

  async startSession({ userId } = {}) {
    this.sid = userId || this.sid || null;
    this._startFlushTimer();
    return this.sid;
  }

  async endSession() {
    await this._flushEvents();
    this._stopFlushTimer();
    this.sid = null;
  }

  trackImpression() {
    // NS はページ表示単体のインプレッション計測を持たない — no-op
  }

  // ============================================
  // メッセージ記録
  // ============================================

  async recordMessage({ role } = {}) {
    if (!role) return;
    this._push(role === "user" ? "message_sent" : "message_received");
  }

  // ============================================
  // イベント記録
  // ============================================

  trackEvent(eventType) {
    this._push(eventType);
  }

  trackModeSwitch(_fromMode, toMode) {
    this._push(toMode === "realtime" ? "voice_start" : "voice_end");
  }

  trackNavigation() {
    this._push("navigate");
  }

  trackQuickAction() {
    this._push("quick_action");
  }

  trackError() {
    this._push("error");
  }

  // ============================================
  // 内部
  // ============================================

  _push(name) {
    if (!name || !analyticsEnabled()) return;
    this._buffer.push({ n: String(name) });
    if (this._buffer.length >= MAX_BATCH) {
      this._flushEvents();
    }
  }

  async _flushEvents() {
    if (!analyticsEnabled() || this._buffer.length === 0) return;
    let events = this._buffer.splice(0, MAX_BATCH);
    // 8KB 上限の粗いガード: 超過分は末尾から間引く
    while (events.length > 1 && JSON.stringify({ sid: this.sid, events }).length > MAX_BYTES) {
      events = events.slice(0, -1);
    }
    try {
      await nsFetch("events", {
        method: "POST",
        body: JSON.stringify({ sid: this.sid || undefined, events }),
      });
    } catch (error) {
      console.warn("[NsAnalytics] flush failed:", error && error.message);
    }
  }

  _startFlushTimer() {
    this._stopFlushTimer();
    this._flushTimer = setInterval(() => this._flushEvents(), FLUSH_INTERVAL_MS);
  }

  _stopFlushTimer() {
    if (this._flushTimer) {
      clearInterval(this._flushTimer);
      this._flushTimer = null;
    }
  }

  _setupBeaconListeners() {
    if (typeof window === "undefined" || typeof window.addEventListener !== "function") return;
    const handleUnload = () => {
      if (!analyticsEnabled() || this._buffer.length === 0) return;
      const events = this._buffer.splice(0, MAX_BATCH);
      try {
        const payload = JSON.stringify({ sid: this.sid || undefined, events });
        if (navigator.sendBeacon) {
          navigator.sendBeacon(restEventsUrl(), new Blob([payload], { type: "application/json" }));
        }
      } catch (_e) {
        /* best-effort */
      }
    };
    window.addEventListener("pagehide", handleUnload);
    window.addEventListener("beforeunload", handleUnload);
  }
}

export const nsAnalytics = new NsAnalytics();
