import path from "node:path";
import fs from "node:fs/promises";
import yaml from "js-yaml";
import { XMLParser } from "fast-xml-parser";

const JAMBOX_NUMBERS_URL = "https://www.jambox.pl/xml/jamboxwliczbach.xml";

/**
 * Proste auth, żeby nikt z internetu nie mógł Ci pisać po YAML.
 * .env: JAMBOX_ADMIN_TOKEN="..."
 */
function isAuthorized(request) {
  const expected = import.meta.env.JAMBOX_ADMIN_TOKEN;
  if (!expected) return false;
  const token = request.headers.get("x-admin-token");
  return token === expected;
}

async function fetchXml(url) {
  const res = await fetch(url);
  if (!res.ok) {
    throw new Error(`Błąd pobierania XML: ${res.status} ${res.statusText}`);
  }
  return await res.text();
}

function parseCountsNode(xmlText) {
  const parser = new XMLParser({
    ignoreAttributes: false,
    attributeNamePrefix: "@_",
  });

  const json = parser.parse(xmlText);
  const node = json.xml?.node ?? json.node ?? null;

  if (!node) {
    throw new Error("Nie znaleziono <node> w jamboxwliczbach.xml");
  }

  return node;
}

function getInt(node, key) {
  const raw = node?.[key];
  const n = Number(raw);
  return Number.isFinite(n) ? n : null;
}

/**
 * Mapowanie kluczy XML na source+slug (tak jak w Twoim starym skrypcie)
 */
function xmlKeyFor(source, slug, isHd) {
  const s = String(source || "").toUpperCase();
  const sl = String(slug || "").toLowerCase();

  // EVIO: ilosc_kanalow_eviooptimum / ilosc_kanalow_hd_eviooptimum
  if (s === "EVIO") {
    return isHd ? `ilosc_kanalow_hd_evio${sl}` : `ilosc_kanalow_evio${sl}`;
  }

  // PLUS: ilosc_kanalow_korzystny / ilosc_kanalow_hd_korzystny
  if (s === "PLUS") {
    return isHd ? `ilosc_kanalow_hd_${sl}` : `ilosc_kanalow_${sl}`;
  }

  return null;
}

function findParamIndex(params, key) {
  return params.findIndex(
    (p) => String(p?.klucz ?? "").toLowerCase() === key.toLowerCase(),
  );
}

export async function POST({ request }) {
  try {
    if (!isAuthorized(request)) {
      return new Response(JSON.stringify({ ok: false, error: "Unauthorized" }), {
        status: 401,
        headers: { "Content-Type": "application/json" },
      });
    }

    const body = await request.json().catch(() => ({}));
    const dryRun = body?.dryRun === true;


    const YAML_PATH =
      import.meta.env.JAMBOX_TV_YAML_PATH ||
      path.join(process.cwd(), "src", "content", "internet-telewizja", "cards.yaml");

    // 1) XML
    const xml = await fetchXml(JAMBOX_NUMBERS_URL);
    const node = parseCountsNode(xml);

    // 2) YAML
    const rawYaml = await fs.readFile(YAML_PATH, "utf8");
    const doc = yaml.load(rawYaml);

    if (!doc || !Array.isArray(doc.cards)) {
      return new Response(JSON.stringify({ ok: false, error: "YAML: brak doc.cards" }), {
        status: 400,
        headers: { "Content-Type": "application/json" },
      });
    }

    const changedItems = [];
    const unchangedItems = [];
    const skippedItems = [];

    for (const card of doc.cards) {
      const id = card?.id ?? null;
      const source = String(card?.source ?? "");
      const slug = String(card?.slug ?? "");

      if (!source || !slug) {
        skippedItems.push({ id, reason: "brak source/slug" });
        continue;
      }

      const params = Array.isArray(card?.parametry) ? card.parametry : [];
      const iCanals = findParamIndex(params, "canals");
      const iHd = findParamIndex(params, "canalshd");

      // nie dopisujemy na siłę, tylko aktualizujemy to co istnieje
      if (iCanals === -1 && iHd === -1) {
        skippedItems.push({ id, source, slug, reason: "brak canals/canalshd w parametry" });
        continue;
      }

      const keyCanals = xmlKeyFor(source, slug, false);
      const keyHd = xmlKeyFor(source, slug, true);

      const xmlCanals = keyCanals ? getInt(node, keyCanals) : null;
      const xmlHd = keyHd ? getInt(node, keyHd) : null;

      if (xmlCanals == null && xmlHd == null) {
        skippedItems.push({
          id,
          source,
          slug,
          reason: "brak wartości w XML",
          keys: { keyCanals, keyHd },
        });
        continue;
      }

      const before = {
        canals: iCanals !== -1 ? Number(params[iCanals]?.value) : null,
        canalshd: iHd !== -1 ? Number(params[iHd]?.value) : null,
      };

      const after = {
        canals: xmlCanals ?? before.canals,
        canalshd: xmlHd ?? before.canalshd,
      };

      const willChange =
        (after.canals != null && before.canals !== after.canals) ||
        (after.canalshd != null && before.canalshd !== after.canalshd);

      if (!willChange) {
        unchangedItems.push({ id, source, slug, before });
        continue;
      }

      if (!dryRun) {
        if (iCanals !== -1 && after.canals != null) params[iCanals].value = after.canals;
        if (iHd !== -1 && after.canalshd != null) params[iHd].value = after.canalshd;
        card.parametry = params;
      }

      changedItems.push({ id, source, slug, before, after, keys: { keyCanals, keyHd } });
    }

    if (!dryRun && changedItems.length > 0) {
      const newYaml = yaml.dump(doc, {
        lineWidth: -1,
        noRefs: true,
        sortKeys: false,
      });
      await fs.writeFile(YAML_PATH, newYaml, "utf8");
    }

    return new Response(
      JSON.stringify({
        ok: true,
        dryRun,
        yamlPath: YAML_PATH,
        changed: changedItems.length,
        unchanged: unchangedItems.length,
        skipped: skippedItems.length,
        changedItems,
        skippedItems,
      }),
      { status: 200, headers: { "Content-Type": "application/json" } },
    );
  } catch (err) {
    console.error("update-channels error:", err);
    return new Response(JSON.stringify({ ok: false, error: String(err?.message ?? err) }), {
      status: 500,
      headers: { "Content-Type": "application/json" },
    });
  }
}
