#!/usr/bin/env node
// Fetch and update cable monitoring mock data for 32 slots (0-31)
// Writes to mocks/device-cgi-simulator/chartsData/cable-monitoring-data/slot{N}/{isolationswiderstand|schleifenwiderstand}/DIA{0|1|2}.json
// Usage examples (PowerShell):
//   node mocks/scripts/fetchCableData.mjs --base https://10.10.0.118 --from 2025-07-13 --to 2025-08-12 --insecure
//   node mocks/scripts/fetchCableData.mjs --slots 0-3 --modes DIA0,DIA1 --types iso --insecure

import fs from "node:fs/promises";
import path from "node:path";
import https from "node:https";

// Simple CLI args parser supporting "--key=value" and "--key value"
const args = (() => {
  const out = {};
  const argv = process.argv.slice(2);
  for (let i = 0; i < argv.length; i++) {
    const tok = argv[i];
    if (tok.startsWith("--")) {
      const eq = tok.indexOf("=");
      if (eq !== -1) {
        const key = tok.slice(2, eq);
        const val = tok.slice(eq + 1);
        out[key] = val;
      } else {
        const key = tok.slice(2);
        const next = argv[i + 1];
        if (next && !next.startsWith("--")) {
          out[key] = next;
          i++;
        } else {
          out[key] = true;
        }
      }
    }
  }
  return out;
})();

const BASE_URL =
  args.base || process.env.CPL_DEVICE_BASE_URL || "https://10.10.0.118";
const MODES = String(args.modes || "DIA0,DIA1,DIA2")
  .split(",")
  .map((s) => s.trim())
  .filter(Boolean);
const TYPES = String(args.types || "iso,rsl")
  .split(",")
  .map((s) => s.trim())
  .filter(Boolean); // iso -> 3, rsl -> 4
const SLOTS = (() => {
  if (args.slots) {
    if (String(args.slots).includes("-")) {
      const [a, b] = String(args.slots).split("-").map(Number);
      return Array.from({ length: b - a + 1 }, (_, i) => a + i);
    }
    return String(args.slots)
      .split(",")
      .map((s) => Number(s.trim()));
  }
  return Array.from({ length: 32 }, (_, i) => i);
})();

const today = new Date();
const defaultFrom = new Date(today);
defaultFrom.setDate(today.getDate() - 30);

const fromISO =
  args.from ||
  process.env.CPL_FROM_DATE ||
  defaultFrom.toISOString().slice(0, 10); // YYYY-MM-DD
const toISO =
  args.to || process.env.CPL_TO_DATE || today.toISOString().slice(0, 10);

// Default output directory matches Next.js API handler slotDataAPIHandler.ts
// (mocks/device-cgi-simulator/chartsData/cable-monitoring-data)
const OUT_DIR =
  args.out ||
  path.join(
    process.cwd(),
    "mocks",
    "device-cgi-simulator",
    "chartsData",
    "cable-monitoring-data"
  );
const INSECURE = Boolean(args.insecure || process.env.CPL_INSECURE);
if (INSECURE) {
  // Allow self-signed certs for local device
  process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
}

// Basic Auth credentials (same default as fetchSystemData.mjs)
const USERNAME = args.user || process.env.CPL_USER || "Littwin";
const PASSWORD = args.pass || process.env.CPL_PASS || "Littwin";
const AUTH_HEADER =
  "Basic " + Buffer.from(`${USERNAME}:${PASSWORD}`).toString("base64");

const sleep = (ms) => new Promise((r) => setTimeout(r, ms));

const toACPDate = (iso) => {
  const [y, m, d] = iso.split("-");
  return `${y};${m};${d}`;
};

const typeToFolderAndCode = (typeKey) => {
  switch (typeKey) {
    case "iso":
      return { folder: "isolationswiderstand", code: 3 };
    case "rsl":
    case "schleife":
      return { folder: "schleifenwiderstand", code: 4 };
    default:
      throw new Error(`Unknown type '${typeKey}'. Use iso or rsl.`);
  }
};

const buildUrl = (mode, from, to, slot, typeCode) =>
  `${BASE_URL}/CPL?seite.ACP&${mode}=${toACPDate(from)};${toACPDate(
    to
  )};${slot};${typeCode};`;

async function fetchJson(url) {
  // Prefer node-fetch when INSECURE to pass https.Agent; otherwise use global fetch when available
  let doFetch = globalThis.fetch;
  if (INSECURE || typeof doFetch === "undefined") {
    const { default: nf } = await import("node-fetch");
    doFetch = nf;
  }
  const init = { headers: { Authorization: AUTH_HEADER } };
  if (INSECURE) {
    init.agent = new https.Agent({ rejectUnauthorized: false });
  }
  const res = await doFetch(url, init);
  if (!res.ok) {
    const text = await res.text().catch(() => "");
    throw new Error(`HTTP ${res.status} ${res.statusText} for ${url}\n${text}`);
  }
  return res.json();
}

async function ensureDir(dir) {
  await fs.mkdir(dir, { recursive: true });
}

async function writeJson(file, data) {
  await ensureDir(path.dirname(file));
  await fs.writeFile(file, JSON.stringify(data, null, 2), "utf8");
}

async function main() {
  console.log(`➡️  Fetch cable data`);
  console.log(`   Base: ${BASE_URL}`);
  console.log(`   Range: ${fromISO} → ${toISO}`);
  console.log(`   Slots: ${SLOTS.join(",")}`);
  console.log(`   Modes: ${MODES.join(",")}`);
  console.log(`   Types: ${TYPES.join(",")}`);
  console.log(`   Out: ${OUT_DIR}`);
  if (INSECURE) console.log(`   TLS: insecure (self-signed allowed)`);

  // Small concurrency to avoid hammering the device
  const MAX_CONCURRENCY = Number(args.concurrency || 3);
  let running = 0;
  let idx = 0;

  const tasks = [];
  for (const slot of SLOTS) {
    for (const typeKey of TYPES) {
      const { folder, code } = typeToFolderAndCode(typeKey);
      for (const mode of MODES) {
        tasks.push({ slot, typeKey, folder, code, mode });
      }
    }
  }

  const runNext = async () => {
    if (idx >= tasks.length) return;
    const task = tasks[idx++];
    running++;
    try {
      const url = buildUrl(task.mode, fromISO, toISO, task.slot, task.code);
      console.log(`→ [slot ${task.slot}] ${task.folder} ${task.mode}`);
      const data = await fetchJson(url);
      const file = path.join(
        OUT_DIR,
        `slot${task.slot}`,
        task.folder,
        `${task.mode}.json`
      );
      await writeJson(file, data);
    } catch (e) {
      console.error(
        `✖ Fehler bei slot ${task.slot} ${task.folder} ${task.mode}:`,
        e.message || e
      );
    } finally {
      running--;
      // polite delay between requests
      await sleep(Number(args.delay || 150));
      if (idx < tasks.length) runNext();
    }
  };

  // Start initial workers
  const starters = Math.min(MAX_CONCURRENCY, tasks.length);
  for (let i = 0; i < starters; i++) runNext();

  // Wait for all to finish
  while (running > 0 || idx < tasks.length) {
    await sleep(100);
  }

  console.log("✅ Fertig.");
}

main().catch((e) => {
  console.error("Unerwarteter Fehler:", e);
  process.exit(1);
});

/*
kann ich auch mit node die isolationswiderstand DIA0 bis DIA2 für den Slot 0 aufrufen

fetchCableData.mjs
:175
I’ll show the exact Node commands to fetch Isolationswiderstand (type 3) for slot 0 across DIA0–DIA2 with the new script.

Checklist

Slot 0 only
Type iso (Isolationswiderstand)
All modes DIA0, DIA1, DIA2
Optional explicit date range
Basic Auth + self-signed TLS
Run (last 30 days, all DIA modes)
node .\mocks\scripts\fetchCableData.mjs --slots 0 --types iso --insecure

node .\mocks\scripts\fetchCableData.mjs --slots 0 --types iso --insecure
Run with explicit date range (e.g., 2025-07-13 → 2025-08-12)
node .\mocks\scripts\fetchCableData.mjs --slots 0 --types iso --from 2025-07-13 --to 2025-08-12 --insecure

node .\mocks\scripts\fetchCableData.mjs --slots 0 --types iso --from 2025-07-13 --to 2025-08-12 --insecure
Add credentials explicitly (if needed)
node .\mocks\scripts\fetchCableData.mjs --slots 0 --types iso --from 2025-07-13 --to 2025-08-12 --user Littwin --pass Littwin --insecure

node .\mocks\scripts\fetchCableData.mjs --slots 0 --types iso --from 2025-07-13 --to 2025-08-12 --user Littwin --pass Littwin --insecure
Notes

By default, the script fetches all modes DIA0,DIA1,DIA2; you can restrict with: --modes DIA0,DIA1,DIA2.
Output goes to:
mocks/device-cgi-simulator/cable-monitoring-data/slot0/isolationswiderstand/DIA{0|1|2}.json
The --insecure flag accepts the device’s self‑signed certificate.
//----

npm run mocks:cable--silent , npm wartet bis das fertig ist

*/
