/**
 * TrackerEngine
 * Reads evolutionScore from MemoryKernel (Phase 6.1)
 * Updates weights, detects trends, logs history
 */
import { LongTermMemory as MemoryKernel } from '../../lib/memory/long_term_memory';

import { loadRegistry, saveRegistry, upsertPolicy } from './registry';
import { appendHistory } from './history_logger';
import { decideTrend, nextStatus } from './trend_analyzer';
import { PolicyMeta, PolicyHistoryRecord } from './policy_types';
import { PolicyConfig } from '../../config/policy.config';
import { clamp, momentum, sign } from '../utils/math_utils';

function ensurePoliciesFromLastSnapshot(reg: PolicyMeta[]) {
  const state = MemoryKernel.getState();
  const last = state.snapshots[state.snapshots.length - 1];
  if (!last) return reg;
  for (const o of last.outcomes) {
    upsertPolicy(reg, { policyId: o.policyId });
  }
  return reg;
}

export function updateAllPolicies() {
  const state = MemoryKernel.getState();
  const evolutionScore = state.metrics?.evolutionScore ?? 0;
  let registry = loadRegistry();
  registry = ensurePoliciesFromLastSnapshot(registry);

  const updated: PolicyMeta[] = [];

  for (const item of registry) {
    const oldW = item.weight;
    const rawDelta = evolutionScore * PolicyConfig.learningRate;
    const prevDelta = item._lastDelta ?? 0;
    const smoothDelta = momentum(rawDelta, prevDelta);
    const newW = clamp(oldW + smoothDelta, PolicyConfig.minWeight, PolicyConfig.maxWeight);

    const trend = decideTrend(oldW, newW);
    const status = nextStatus(item, newW);
    const corr: -1 | 0 | 1 = (sign(newW - oldW) * sign(evolutionScore)) as -1 | 0 | 1;

    const updatedMeta: PolicyMeta = {
      ...item,
      weight: newW,
      trend,
      status,
      lastUpdate: new Date().toISOString(),
      _lastDelta: rawDelta,
    };

    if (newW !== oldW) {
      const rec: PolicyHistoryRecord = {
        policyId: item.policyId,
        oldWeight: oldW,
        newWeight: newW,
        trend,
        timestamp: updatedMeta.lastUpdate,
        reason: trendReason(trend, evolutionScore),
        correlation: corr,
      };
      appendHistory(rec);
    }

    updated.push(updatedMeta);
  }

  saveRegistry(updated);
  return { evolutionScore, updatedCount: updated.length, registry: updated };
}

function trendReason(trend: '↑' | '↓' | '→', evo: number) {
  if (trend === '↑') return `Weight increased due to positive evolutionScore (${evo.toFixed(4)})`;
  if (trend === '↓')
    return `Weight decreased due to negative/weak evolutionScore (${evo.toFixed(4)})`;
  return `Weight preserved (neutral vs evolutionScore ${evo.toFixed(4)})`;
}
