// report-reader.mjs — Aggregates sessions.jsonl into a JSON summary.
// Dual-mode: importable (named exports) or directly executable.
// Backward-compatible with v1.0.0 records that lack pushback / domain_context.

import { readFileSync, existsSync } from 'fs';

export function readSessions(path) {
  if (!existsSync(path)) return [];
  return readFileSync(path, 'utf8')
    .split('\n')
    .filter(Boolean)
    .map(line => {
      try { return JSON.parse(line); } catch { return null; }
    })
    .filter(Boolean);
}

export function aggregateSessions(sessions) {
  let pushback_total = 0;
  let relationship_domain_count = 0;
  let other_domain_count = 0;
  let null_domain_count = 0;
  let v1_0_records = 0;
  let v1_1_records = 0;
  let v1_2_records = 0;

  let total_end_records = 0;
  let total_dependency = 0;
  let total_escalation = 0;
  let total_fatigue = 0;
  let total_validation = 0;

  // v1.2: per-domain counters (each session that includes domain X increments
  // domain_breakdown[X] by 1 — multi-domain sessions increment multiple).
  const domain_breakdown = {
    relationship: 0, legal: 0, parenting: 0, health: 0, financial: 0,
    professional: 0, spirituality: 0, consumer: 0, personal_dev: 0,
  };
  // v1.2: user_info_class distribution.
  const user_info_distribution = {
    yes_people: 0, yes_digital: 0, no: 0, null: 0,
  };
  // v1.2: valseek summary.
  let valseek_sessions = 0;       // sessions with valseek_count > 0
  let valseek_total = 0;          // sum of valseek_count across all v1.2 records
  // v1.2: aggregated stakes signal — sum of max-domain-weight across sessions.
  // (Reported as part of /interaction-report; raw aggregate.)
  let stakes_signal_total = 0;
  let stakes_signal_sessions = 0;

  // Domain stakes table mirrors lib.mjs DOMAIN_STAKES so report-reader stays
  // standalone (no cross-import). Keep in sync with lib.mjs.
  const DOMAIN_STAKES = {
    legal: 1.5, parenting: 1.5, health: 1.5, financial: 1.5,
    relationship: 1.3, spirituality: 1.2, professional: 1.1,
    wellbeing: 1.2, lifepath: 1.1, values: 1.2,
    personal_dev: 1.0, consumer: 1.0,
  };

  for (const rec of sessions) {
    if (!rec || rec.note === 'no_state_file') continue;
    if (rec.duration_min === undefined) continue;

    total_end_records += 1;
    const flags = rec.flags || {};

    const pushback = flags.pushback;
    // v1.2 discriminator: presence of user_info_class field marks a v1.2 record.
    const hasUserInfoClass = Object.prototype.hasOwnProperty.call(rec, 'user_info_class');
    if (hasUserInfoClass) v1_2_records += 1;
    else if (pushback === undefined || pushback === null) v1_0_records += 1;
    else v1_1_records += 1;

    pushback_total += Number(pushback) || 0;
    total_dependency += Number(flags.dependency) || 0;
    total_escalation += Number(flags.escalation) || 0;
    total_fatigue += Number(flags.fatigue) || 0;
    total_validation += Number(flags.validation) || 0;

    // v1.2: domain_context is array; v1.0/v1.1: null or string. Coerce on read.
    const dc = rec.domain_context;
    const domains = Array.isArray(dc) ? dc : (dc ? [dc] : []);
    if (domains.length === 0) null_domain_count += 1;
    else if (domains.includes('relationship')) relationship_domain_count += 1;
    else other_domain_count += 1;

    // v1.2: per-domain breakdown (multi-domain sessions count once per domain).
    for (const d of domains) {
      if (Object.prototype.hasOwnProperty.call(domain_breakdown, d)) {
        domain_breakdown[d] += 1;
      }
    }

    // v1.2 fields
    if (hasUserInfoClass) {
      const cls = rec.user_info_class;
      if (cls === 'yes_people' || cls === 'yes_digital' || cls === 'no') {
        user_info_distribution[cls] += 1;
      } else {
        user_info_distribution.null += 1;
      }

      const vs = Number(rec.valseek_count) || 0;
      valseek_total += vs;
      if (vs > 0) valseek_sessions += 1;

      // stakes_signal: max weight among the session's domains.
      if (domains.length > 0) {
        let maxW = 1.0;
        for (const d of domains) {
          const w = DOMAIN_STAKES[d];
          if (typeof w === 'number' && w > maxW) maxW = w;
        }
        stakes_signal_total += maxW;
        stakes_signal_sessions += 1;
      }
    }
  }

  return {
    pushback_total,
    relationship_domain_count,
    other_domain_count,
    null_domain_count,
    total_end_records,
    flags_total: {
      dependency: total_dependency,
      escalation: total_escalation,
      fatigue: total_fatigue,
      validation: total_validation,
      pushback: pushback_total,
    },
    schema_version: {
      v1_0_records,
      v1_1_records,
      v1_2_records,
    },
    // v1.2 aggregations
    domain_breakdown,
    user_info_class: user_info_distribution,
    valseek: {
      sessions: valseek_sessions,
      total: valseek_total,
    },
    stakes_signal: {
      sum: stakes_signal_total,
      sessions: stakes_signal_sessions,
      mean: stakes_signal_sessions > 0
        ? Number((stakes_signal_total / stakes_signal_sessions).toFixed(2))
        : 0,
    },
  };
}

if (import.meta.url === `file://${process.argv[1]}`) {
  const path = process.argv[2];
  if (!path) {
    process.stderr.write('Usage: node report-reader.mjs <path-to-sessions.jsonl>\n');
    process.exit(1);
  }
  const result = aggregateSessions(readSessions(path));
  process.stdout.write(JSON.stringify(result, null, 2) + '\n');
}
