const fs = require("fs");
const { DATA_DIR } = require("../hijack-monitoring/store");
const { atlasState } = require("../atlas-probes");

const ASPA_ADOPTION_FILE = DATA_DIR + '/aspa-adoption-history.json';

// Load persisted ASPA adoption history from disk.
// Returns array of snapshot objects (up to 365 entries).
function loadAspaAdoptionHistory() {
  try {
    const raw = JSON.parse(fs.readFileSync(ASPA_ADOPTION_FILE, 'utf8'));
    return Array.isArray(raw) ? raw : [];
  } catch(_) { return []; }
}

// Save ASPA adoption history to disk (keep last 365 entries).
function saveAspaAdoptionHistory(history) {
  try {
    const trimmed = history.slice(-365);
    fs.writeFileSync(ASPA_ADOPTION_FILE, JSON.stringify(trimmed, null, 2), 'utf8');
  } catch(e) {
    console.error('[ASPA-ADOPT] Save failed:', e.message);
  }
}

// In-memory adoption history (persisted on each new snapshot). Mutated
// in place (push / index-assign), never reassigned -- safe to export as a
// live array reference, same pattern as roaStore/pdbSourceCache.
let aspaAdoptionDailyHistory = loadAspaAdoptionHistory();

// Take a new adoption snapshot and persist it. Called whenever the RPKI feed
// is refreshed.
// @param {number} aspaCount   — total ASPA objects in rpkiAspaMap
// @param {number} roaCount    — total ROAs in roaStore
// @param {Map}    rpkiAspaMap — customer_asid -> Set<provider_asn>, owned by
//   server/services/rpki.js; passed in explicitly (rather than required here)
//   to avoid a circular require between this module and rpki.js.
function recordAspaAdoptionSnapshot(aspaCount, roaCount, rpkiAspaMap) {
  const now    = new Date();
  const date   = now.toISOString().slice(0, 10); // "YYYY-MM-DD"

  // Compute how many Atlas-visible ASNs have ASPA
  let atlasTotal   = 0;
  let atlasWithAspa = 0;
  if (atlasState.cache?.asns_with_probes) {
    atlasTotal = atlasState.cache.asns_with_probes.length;
    // rpkiAspaMap is keyed by integer ASN
    atlasWithAspa = atlasState.cache.asns_with_probes.filter(a => rpkiAspaMap.has(Number(a))).length;
  }

  const coveragePct = atlasTotal > 0
    ? Math.round((atlasWithAspa / atlasTotal) * 10000) / 100  // 2 decimal places
    : 0;

  // Compute delta from previous snapshot
  const prev  = aspaAdoptionDailyHistory[aspaAdoptionDailyHistory.length - 1];
  const delta = prev ? aspaCount - prev.aspa_objects : 0;

  const snapshot = {
    date,
    ts: now.getTime(),
    aspa_objects: aspaCount,
    roa_count: roaCount,
    atlas_asns_total: atlasTotal,
    atlas_asns_with_aspa: atlasWithAspa,
    coverage_pct_atlas: coveragePct,
    aspa_delta: delta,
    method: 'rpki_cloudflare_feed',
  };

  // Only store one snapshot per date (overwrite if same day)
  const existingIdx = aspaAdoptionDailyHistory.findIndex(s => s.date === date);
  if (existingIdx >= 0) {
    aspaAdoptionDailyHistory[existingIdx] = snapshot;
  } else {
    aspaAdoptionDailyHistory.push(snapshot);
  }
  saveAspaAdoptionHistory(aspaAdoptionDailyHistory);
  console.log(`[ASPA-ADOPT] Snapshot ${date}: ${aspaCount} objects, ${coveragePct}% Atlas coverage (${atlasWithAspa}/${atlasTotal})`);
  return snapshot;
}

// Get adoption trend for a given period string ('7d', '30d', '90d', '1y').
function getAdoptionTrend(period) {
  const days = period === '7d' ? 7 : period === '30d' ? 30 : period === '90d' ? 90 : 365;
  const cutoff = Date.now() - days * 24 * 60 * 60 * 1000;
  return aspaAdoptionDailyHistory.filter(s => s.ts >= cutoff);
}

// Build the ASPA adoption dashboard HTML.
function buildAspaAdoptionDashboard() {
  const latest   = aspaAdoptionDailyHistory[aspaAdoptionDailyHistory.length - 1];
  const trend30  = getAdoptionTrend('30d');
  const trend7   = getAdoptionTrend('7d');

  // Forecast: simple linear regression over last 30 days
  function linearForecast(data, daysAhead) {
    if (data.length < 2) return null;
    const n = data.length;
    const xs = data.map((_, i) => i);
    const ys = data.map(d => d.coverage_pct_atlas);
    const xMean = xs.reduce((a, b) => a + b, 0) / n;
    const yMean = ys.reduce((a, b) => a + b, 0) / n;
    const num = xs.reduce((s, x, i) => s + (x - xMean) * (ys[i] - yMean), 0);
    const den = xs.reduce((s, x) => s + (x - xMean) ** 2, 0);
    if (den === 0) return yMean;
    const slope = num / den;
    return Math.max(0, Math.min(100, yMean + slope * (n - 1 + daysAhead)));
  }

  const forecast90d  = linearForecast(trend30, 90);
  const change7d     = trend7.length >= 2
    ? (trend7[trend7.length-1].aspa_objects - trend7[0].aspa_objects)
    : 0;
  const trendLabels  = trend30.map(d => d.date);
  const trendValues  = trend30.map(d => d.coverage_pct_atlas);
  const asnValues    = trend30.map(d => d.aspa_objects);

  const coverageNow  = latest?.coverage_pct_atlas ?? 0;
  const aspaNow      = latest?.aspa_objects ?? 0;
  const atlasTotal   = latest?.atlas_asns_total ?? 0;

  return `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8"/>
  <meta name="viewport" content="width=device-width,initial-scale=1"/>
  <title>ASPA Adoption Tracker · PeerCortex</title>
  <script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
  <style>
    *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
    body{font-family:-apple-system,'Segoe UI',system-ui,sans-serif;background:#f5f3ff;color:#1e1b4b;min-height:100vh}
    nav{background:#4f46e5;color:#fff;padding:14px 24px;display:flex;align-items:center;gap:12px}
    nav .logo{font-size:16px;font-weight:700;letter-spacing:-0.5px}
    nav .logo span{opacity:0.7;font-weight:400}
    nav a{color:rgba(255,255,255,0.8);text-decoration:none;font-size:13px;margin-left:16px}
    nav a:hover{color:#fff}
    .container{max-width:1100px;margin:0 auto;padding:24px 20px}
    h1{font-size:22px;font-weight:700;color:#3730a3;margin-bottom:4px}
    .subtitle{font-size:13px;color:#6b7280;margin-bottom:24px}
    .grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:16px;margin-bottom:28px}
    .card{background:#fff;border:1px solid #e0e7ff;border-radius:12px;padding:18px 20px;box-shadow:0 1px 3px rgba(79,70,229,.08)}
    .card .label{font-size:10px;color:#6b7280;text-transform:uppercase;letter-spacing:0.7px;margin-bottom:6px}
    .card .value{font-size:28px;font-weight:700;color:#4f46e5;line-height:1}
    .card .unit{font-size:11px;color:#9ca3af;margin-top:4px}
    .card.green .value{color:#16a34a}
    .card.amber .value{color:#d97706}
    .chart-wrap{background:#fff;border:1px solid #e0e7ff;border-radius:12px;padding:20px;margin-bottom:24px;box-shadow:0 1px 3px rgba(79,70,229,.08)}
    .chart-wrap h2{font-size:14px;font-weight:600;color:#3730a3;margin-bottom:16px}
    .chart-row{display:grid;grid-template-columns:2fr 1fr;gap:20px;margin-bottom:24px}
    .export-bar{display:flex;gap:10px;margin-bottom:20px;flex-wrap:wrap}
    .btn{padding:8px 16px;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer;text-decoration:none;border:none}
    .btn-primary{background:#4f46e5;color:#fff}
    .btn-outline{background:#fff;color:#4f46e5;border:1.5px solid #4f46e5}
    .btn:hover{opacity:0.9}
    .forecast-box{background:linear-gradient(135deg,#4f46e5,#6366f1);color:#fff;border-radius:12px;padding:18px 22px}
    .forecast-box .label{font-size:10px;opacity:0.8;text-transform:uppercase;letter-spacing:0.7px;margin-bottom:6px}
    .forecast-box .value{font-size:32px;font-weight:700;line-height:1}
    .forecast-box .unit{font-size:11px;opacity:0.7;margin-top:4px}
    .meta{font-size:11px;color:#9ca3af;margin-top:24px;text-align:center}
    @media(max-width:700px){.chart-row{grid-template-columns:1fr}}
  </style>
</head>
<body>
<nav>
  <span class="logo">⬡ PeerCortex <span>Network Intelligence</span></span>
  <a href="/">Dashboard</a>
  <a href="/aspa-adoption">ASPA Tracker</a>
</nav>
<div class="container">
  <h1>ASPA Adoption Tracker</h1>
  <p class="subtitle">Global ASPA deployment trends · Powered by RPKI Cloudflare feed · Updated every ~4 hours</p>

  <div class="grid">
    <div class="card ${coverageNow >= 15 ? 'green' : 'amber'}">
      <div class="label">Atlas Coverage</div>
      <div class="value">${coverageNow.toFixed(1)}%</div>
      <div class="unit">of Atlas-visible ASNs</div>
    </div>
    <div class="card">
      <div class="label">ASPA Objects</div>
      <div class="value">${aspaNow.toLocaleString()}</div>
      <div class="unit">total in RPKI</div>
    </div>
    <div class="card">
      <div class="label">Atlas ASNs</div>
      <div class="value">${atlasTotal.toLocaleString()}</div>
      <div class="unit">sampled denominator</div>
    </div>
    <div class="card ${change7d > 0 ? 'green' : ''}">
      <div class="label">7-Day Delta</div>
      <div class="value">${change7d > 0 ? '+' : ''}${change7d}</div>
      <div class="unit">new ASPA objects</div>
    </div>
    <div class="card">
      <div class="label">Data Points</div>
      <div class="value">${aspaAdoptionDailyHistory.length}</div>
      <div class="unit">history snapshots</div>
    </div>
  </div>

  <div class="export-bar">
    <a class="btn btn-primary" href="/api/aspa-adoption-stats/export?format=json&period=30d">↓ JSON (30d)</a>
    <a class="btn btn-outline" href="/api/aspa-adoption-stats/export?format=csv&period=30d">↓ CSV (30d)</a>
    <a class="btn btn-outline" href="/api/aspa-adoption-stats/export?format=csv&period=1y">↓ CSV (1y)</a>
    <a class="btn btn-outline" href="/api/export/pdf?asn=0&format=report" style="display:none">PDF Report</a>
  </div>

  <div class="chart-row">
    <div class="chart-wrap">
      <h2>Atlas Coverage % (last 30 days)</h2>
      <canvas id="coverageChart" height="120"></canvas>
    </div>
    <div class="forecast-box">
      <div class="label">90-Day Forecast</div>
      <div class="value">${forecast90d !== null ? forecast90d.toFixed(1) + '%' : '—'}</div>
      <div class="unit">linear projection from 30-day trend</div>
      <div style="margin-top:16px;font-size:11px;opacity:0.8">
        Based on ${trend30.length} data points.<br/>
        Current: ${coverageNow.toFixed(1)}%
      </div>
    </div>
  </div>

  <div class="chart-wrap">
    <h2>Total ASPA Objects in RPKI (last 30 days)</h2>
    <canvas id="asnChart" height="80"></canvas>
  </div>

  <div class="meta">
    Last snapshot: ${latest?.date ?? 'none'} · Denominator: ${atlasTotal.toLocaleString()} Atlas ASNs ·
    <a href="/api/aspa-adoption-stats?period=30d" style="color:#4f46e5">JSON API</a>
  </div>
</div>

<script>
const labels = ${JSON.stringify(trendLabels)};
const covData = ${JSON.stringify(trendValues)};
const asnData = ${JSON.stringify(asnValues)};

const commonOpts = {
  responsive: true,
  plugins: { legend: { display: false } },
  scales: {
    x: { grid: { color: '#f0eeff' }, ticks: { maxRotation: 45, font: { size: 10 } } },
    y: { grid: { color: '#f0eeff' }, ticks: { font: { size: 10 } }, beginAtZero: false }
  }
};

new Chart(document.getElementById('coverageChart'), {
  type: 'line',
  data: {
    labels,
    datasets: [{
      data: covData,
      borderColor: '#4f46e5',
      backgroundColor: 'rgba(79,70,229,0.08)',
      fill: true,
      tension: 0.3,
      pointRadius: 3,
    }]
  },
  options: { ...commonOpts, scales: { ...commonOpts.scales, y: { ...commonOpts.scales.y, ticks: { callback: v => v + '%', font: { size: 10 } } } } }
});

new Chart(document.getElementById('asnChart'), {
  type: 'bar',
  data: {
    labels,
    datasets: [{
      data: asnData,
      backgroundColor: 'rgba(79,70,229,0.6)',
      borderColor: '#4f46e5',
      borderWidth: 1,
    }]
  },
  options: commonOpts
});
</script>
</body>
</html>`;
}

module.exports = {
  aspaAdoptionDailyHistory,
  loadAspaAdoptionHistory,
  saveAspaAdoptionHistory,
  recordAspaAdoptionSnapshot,
  getAdoptionTrend,
  buildAspaAdoptionDashboard,
};
