

const STATUSES = {
  running: { label: "running", dot: "ok",   sym: "●" },
  idle:    { label: "idle",    dot: "info", sym: "○" },
  booting: { label: "booting", dot: "warn", sym: "◐" },
  stopped: { label: "stopped", dot: "mute", sym: "○" },
  error:   { label: "error",   dot: "bad",  sym: "✕" },
};

const TASKS_BY_STATUS = {
  running: ["scraping", "ad-create", "checkout", "monitoring", "captcha-solve", "session-keep"],
  booting: ["warming-up"],
  idle:    ["queued"],
  stopped: ["—"],
  error:   ["halted"],
};

const CODE_PALETTE = [
  { name:'orange', dot:'#FF5F1F', text:'#FF8A55', bg:'rgba(255,95,31,.13)',   border:'rgba(255,95,31,.32)'   },
  { name:'red',    dot:'#FF6B6B', text:'#FF9393', bg:'rgba(255,107,107,.12)', border:'rgba(255,107,107,.3)'  },
  { name:'yellow', dot:'#D7B074', text:'#E8CC9A', bg:'rgba(215,176,116,.12)', border:'rgba(215,176,116,.3)'  },
  { name:'amber',  dot:'#FF9A2E', text:'#FFBB70', bg:'rgba(255,154,46,.12)',  border:'rgba(255,154,46,.3)'   },
  { name:'lime',   dot:'#A8D060', text:'#C4E48A', bg:'rgba(168,208,96,.10)',  border:'rgba(168,208,96,.28)'  },
  { name:'green',  dot:'#5EE083', text:'#90EDAC', bg:'rgba(94,224,131,.10)',  border:'rgba(94,224,131,.28)'  },
  { name:'cyan',   dot:'#5BCFCF', text:'#8DDFDF', bg:'rgba(91,207,207,.10)', border:'rgba(91,207,207,.28)'  },
  { name:'blue',   dot:'#77B1D8', text:'#A3CCEC', bg:'rgba(119,177,216,.10)', border:'rgba(119,177,216,.28)' },
  { name:'violet', dot:'#9B7FE0', text:'#BBA8EC', bg:'rgba(155,127,224,.10)', border:'rgba(155,127,224,.28)' },
  { name:'rose',   dot:'#E07899', text:'#EDAABF', bg:'rgba(224,120,153,.10)', border:'rgba(224,120,153,.28)' },
];

const initialCodes = ["US-EAST-1", "EU-WEST-1", "AP-SOUTHEAST-1"];

function makeColorLookup(codes) {
  const idx = new Map(codes.map((c, i) => [c, i]));
  return (code) => {
    const i = idx.get(code);
    if (i == null) return CODE_PALETTE[CODE_PALETTE.length - 1];
    return CODE_PALETTE[i % CODE_PALETTE.length];
  };
}

const ACCOUNT_PREFIXES = {
  "US-EAST-1":      ["fb.us", "tt.us", "mp.us", "ads.us"],
  "EU-WEST-1":      ["fb.eu", "tt.eu", "mp.eu", "ads.eu"],
  "AP-SOUTHEAST-1": ["fb.apac","tt.apac","mp.apac","ads.apac"],
};

function makeInstances(codes) {
  const out = [];
  const dist = [10, 8, 6]; 
  const statuses = ["running","running","running","running","running","idle","idle","booting","stopped","error"];
  let n = 0;
  codes.forEach((code, ci) => {
    const count = dist[ci] != null ? dist[ci] : 4;
    const prefixes = ACCOUNT_PREFIXES[code] || ["acc"];
    for (let i = 0; i < count; i++) {
      n++;
      const id = "i" + String(n).padStart(4, "0");
      const name = "node-" + Math.random().toString(36).slice(2,6) + "-" + Math.random().toString(36).slice(2,5);
      const status = statuses[(n * 7) % statuses.length];
      const uptime = status === "running" ? `${Math.floor(Math.random()*48)}h ${Math.floor(Math.random()*60)}m` : "—";
      const account = prefixes[i % prefixes.length] + "." + String(i+1).padStart(3, "0");
      const taskPool = TASKS_BY_STATUS[status] || ["—"];
      const task = taskPool[n % taskPool.length];
      out.push({ id, name, status, code, account, uptime, task });
    }
  });
  return out;
}

const LOG_TEMPLATES = [
  ["INFO",  "instance booting…"],
  ["INFO",  "loaded shard {sid}"],
  ["INFO",  "attached to map {code}"],
  ["INFO",  "tcp connection established to upstream"],
  ["DEBUG", "heartbeat ok  ↑{up}ms  ↓{dn}ms"],
  ["INFO",  "session token rotated"],
  ["WARN",  "upstream latency {lat}ms (threshold 250ms)"],
  ["INFO",  "task queue drained ({n} jobs)"],
  ["DEBUG", "snapshot captured ({sz}KB)"],
  ["INFO",  "checkpoint persisted to s3://veil-snap/{id}.bin"],
  ["WARN",  "rate limit headroom <20%, backing off"],
  ["INFO",  "tap → tap.veil.cloud:8443 (latency {lat}ms)"],
  ["ERROR", "upstream reset by peer ECONNRESET — retrying"],
  ["INFO",  "account {acc} session established"],
];

function genLogs(instance, count = 60) {
  const out = [];
  let m = 12, s = 22, ms = 1;
  for (let i = 0; i < count; i++) {
    ms += 20 + Math.floor(Math.random()*900);
    if (ms >= 1000) { s += Math.floor(ms/1000); ms = ms % 1000; }
    if (s >= 60)    { m += Math.floor(s/60); s = s % 60; }
    if (m >= 60)    m = m % 60;
    const tpl = LOG_TEMPLATES[(i * 13 + instance.name.length) % LOG_TEMPLATES.length];
    let msg = tpl[1]
      .replace("{sid}", instance.id.slice(1))
      .replace("{code}", instance.code || "—")
      .replace("{up}",   20 + Math.floor(Math.random()*60))
      .replace("{dn}",   20 + Math.floor(Math.random()*60))
      .replace("{lat}", 180 + Math.floor(Math.random()*220))
      .replace("{n}",    1 + Math.floor(Math.random()*40))
      .replace("{sz}",   8 + Math.floor(Math.random()*128))
      .replace("{id}",   instance.id)
      .replace("{acc}",  instance.account || "?");
    out.push({
      ts: `${String(m).padStart(2,'0')}:${String(s).padStart(2,'0')}.${String(ms).padStart(3,'0')}`,
      level: tpl[0], msg,
    });
  }
  return out;
}

const CODE_NAME_RE = /^[A-Z][A-Z0-9-]{1,23}$/;

Object.assign(window, { STATUSES, CODE_PALETTE, initialCodes, makeColorLookup, makeInstances, genLogs, CODE_NAME_RE, TASKS_BY_STATUS });
