// OpenFang Analytics Page — Full usage analytics with per-model and per-agent breakdowns
// Includes Cost Dashboard with donut chart, bar chart, projections, and provider breakdown.
'use strict';

function analyticsPage() {
  return {
    tab: 'summary',
    summary: {},
    byModel: [],
    byAgent: [],
    loading: true,
    loadError: '',

    // Cost tab state
    dailyCosts: [],
    todayCost: 0,
    firstEventDate: null,

    // Chart colors for providers (stable palette)
    _chartColors: [
      '#FF5C00', '#3B82F6', '#10B981', '#F59E0B', '#8B5CF6',
      '#EC4899', '#06B6D4', '#EF4444', '#84CC16', '#F97316',
      '#6366F1', '#14B8A6', '#E11D48', '#A855F7', '#22D3EE'
    ],

    async loadUsage() {
      this.loading = true;
      this.loadError = '';
      try {
        await Promise.all([
          this.loadSummary(),
          this.loadByModel(),
          this.loadByAgent(),
          this.loadDailyCosts()
        ]);
      } catch(e) {
        this.loadError = e.message || 'Could not load usage data.';
      }
      this.loading = false;
    },

    async loadData() { return this.loadUsage(); },

    async loadSummary() {
      try {
        this.summary = await OpenFangAPI.get('/api/usage/summary');
      } catch(e) {
        this.summary = { total_input_tokens: 0, total_output_tokens: 0, total_cost_usd: 0, call_count: 0, total_tool_calls: 0 };
        throw e;
      }
    },

    async loadByModel() {
      try {
        var data = await OpenFangAPI.get('/api/usage/by-model');
        this.byModel = data.models || [];
      } catch(e) { this.byModel = []; }
    },

    async loadByAgent() {
      try {
        var data = await OpenFangAPI.get('/api/usage');
        this.byAgent = data.agents || [];
      } catch(e) { this.byAgent = []; }
    },

    async loadDailyCosts() {
      try {
        var data = await OpenFangAPI.get('/api/usage/daily');
        this.dailyCosts = data.days || [];
        this.todayCost = data.today_cost_usd || 0;
        this.firstEventDate = data.first_event_date || null;
      } catch(e) {
        this.dailyCosts = [];
        this.todayCost = 0;
        this.firstEventDate = null;
      }
    },

    formatTokens(n) {
      if (!n) return '0';
      if (n >= 1000000) return (n / 1000000).toFixed(2) + 'M';
      if (n >= 1000) return (n / 1000).toFixed(1) + 'K';
      return String(n);
    },

    formatCost(c) {
      if (!c) return '$0.00';
      if (c < 0.01) return '$' + c.toFixed(4);
      return '$' + c.toFixed(2);
    },

    maxTokens() {
      var max = 0;
      this.byModel.forEach(function(m) {
        var t = (m.total_input_tokens || 0) + (m.total_output_tokens || 0);
        if (t > max) max = t;
      });
      return max || 1;
    },

    barWidth(m) {
      var t = (m.total_input_tokens || 0) + (m.total_output_tokens || 0);
      return Math.max(2, Math.round((t / this.maxTokens()) * 100)) + '%';
    },

    // ── Cost tab helpers ──

    avgCostPerMessage() {
      var count = this.summary.call_count || 0;
      if (count === 0) return 0;
      return (this.summary.total_cost_usd || 0) / count;
    },

    projectedMonthlyCost() {
      if (!this.firstEventDate || !this.summary.total_cost_usd) return 0;
      var first = new Date(this.firstEventDate);
      var now = new Date();
      var diffMs = now.getTime() - first.getTime();
      var diffDays = diffMs / (1000 * 60 * 60 * 24);
      if (diffDays < 1) diffDays = 1;
      return (this.summary.total_cost_usd / diffDays) * 30;
    },

    // ── Provider aggregation from byModel data ──

    costByProvider() {
      var providerMap = {};
      var self = this;
      this.byModel.forEach(function(m) {
        var provider = self._extractProvider(m.model);
        if (!providerMap[provider]) {
          providerMap[provider] = { provider: provider, cost: 0, tokens: 0, calls: 0 };
        }
        providerMap[provider].cost += (m.total_cost_usd || 0);
        providerMap[provider].tokens += (m.total_input_tokens || 0) + (m.total_output_tokens || 0);
        providerMap[provider].calls += (m.call_count || 0);
      });
      var result = [];
      for (var key in providerMap) {
        if (providerMap.hasOwnProperty(key)) {
          result.push(providerMap[key]);
        }
      }
      result.sort(function(a, b) { return b.cost - a.cost; });
      return result;
    },

    _extractProvider(modelName) {
      if (!modelName) return 'Unknown';
      var lower = modelName.toLowerCase();
      if (lower.indexOf('claude') !== -1 || lower.indexOf('haiku') !== -1 || lower.indexOf('sonnet') !== -1 || lower.indexOf('opus') !== -1) return 'Anthropic';
      if (lower.indexOf('gemini') !== -1 || lower.indexOf('gemma') !== -1) return 'Google';
      if (lower.indexOf('gpt') !== -1 || lower.indexOf('o1') !== -1 || lower.indexOf('o3') !== -1 || lower.indexOf('o4') !== -1) return 'OpenAI';
      if (lower.indexOf('llama') !== -1 || lower.indexOf('mixtral') !== -1 || lower.indexOf('groq') !== -1) return 'Groq';
      if (lower.indexOf('deepseek') !== -1) return 'DeepSeek';
      if (lower.indexOf('mistral') !== -1) return 'Mistral';
      if (lower.indexOf('command') !== -1 || lower.indexOf('cohere') !== -1) return 'Cohere';
      if (lower.indexOf('grok') !== -1) return 'xAI';
      if (lower.indexOf('jamba') !== -1) return 'AI21';
      if (lower.indexOf('qwen') !== -1) return 'Together';
      return 'Other';
    },

    // ── Donut chart (stroke-dasharray on circles) ──

    donutSegments() {
      var providers = this.costByProvider();
      var total = 0;
      var colors = this._chartColors;
      providers.forEach(function(p) { total += p.cost; });
      if (total === 0) return [];

      var segments = [];
      var offset = 0;
      var circumference = 2 * Math.PI * 60; // r=60
      for (var i = 0; i < providers.length; i++) {
        var pct = providers[i].cost / total;
        var dashLen = pct * circumference;
        segments.push({
          provider: providers[i].provider,
          cost: providers[i].cost,
          percent: Math.round(pct * 100),
          color: colors[i % colors.length],
          dasharray: dashLen + ' ' + (circumference - dashLen),
          dashoffset: -offset,
          circumference: circumference
        });
        offset += dashLen;
      }
      return segments;
    },

    // ── Bar chart (last 7 days) ──

    barChartData() {
      var days = this.dailyCosts;
      if (!days || days.length === 0) return [];
      var maxCost = 0;
      days.forEach(function(d) { if (d.cost_usd > maxCost) maxCost = d.cost_usd; });
      if (maxCost === 0) maxCost = 1;

      var dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
      var result = [];
      for (var i = 0; i < days.length; i++) {
        var d = new Date(days[i].date + 'T12:00:00');
        var dayName = dayNames[d.getDay()] || '?';
        var heightPct = Math.max(2, Math.round((days[i].cost_usd / maxCost) * 120));
        result.push({
          date: days[i].date,
          dayName: dayName,
          cost: days[i].cost_usd,
          tokens: days[i].tokens,
          calls: days[i].calls,
          barHeight: heightPct
        });
      }
      return result;
    },

    // ── Cost by model table (sorted by cost descending) ──

    costByModelSorted() {
      var models = this.byModel.slice();
      models.sort(function(a, b) { return (b.total_cost_usd || 0) - (a.total_cost_usd || 0); });
      return models;
    },

    maxModelCost() {
      var max = 0;
      this.byModel.forEach(function(m) {
        if ((m.total_cost_usd || 0) > max) max = m.total_cost_usd;
      });
      return max || 1;
    },

    costBarWidth(m) {
      return Math.max(2, Math.round(((m.total_cost_usd || 0) / this.maxModelCost()) * 100)) + '%';
    },

    modelTier(modelName) {
      if (!modelName) return 'unknown';
      var lower = modelName.toLowerCase();
      if (lower.indexOf('opus') !== -1 || lower.indexOf('o1') !== -1 || lower.indexOf('o3') !== -1 || lower.indexOf('deepseek-r1') !== -1) return 'frontier';
      if (lower.indexOf('sonnet') !== -1 || lower.indexOf('gpt-4') !== -1 || lower.indexOf('gemini-2.5') !== -1 || lower.indexOf('gemini-1.5-pro') !== -1) return 'smart';
      if (lower.indexOf('haiku') !== -1 || lower.indexOf('gpt-3.5') !== -1 || lower.indexOf('flash') !== -1 || lower.indexOf('mixtral') !== -1) return 'balanced';
      if (lower.indexOf('llama') !== -1 || lower.indexOf('groq') !== -1 || lower.indexOf('gemma') !== -1) return 'fast';
      return 'balanced';
    }
  };
}
