import path from "node:path";
import { XMLParser } from "fast-xml-parser";
import Database from "better-sqlite3";

const FEEDS = [
  { url: "https://www.jambox.pl/xml/listakanalow-smart.xml", name: "Smart" },
  { url: "https://www.jambox.pl/xml/listakanalow-optimum.xml", name: "Optimum" },
  { url: "https://www.jambox.pl/xml/listakanalow-platinum.xml", name: "Platinum" },
  { url: "https://www.jambox.pl/xml/listakanalow-pluspodstawowy.xml", name: "Podstawowy" },
  { url: "https://www.jambox.pl/xml/listakanalow-pluskorzystny.xml", name: "Korzystny" },
  { url: "https://www.jambox.pl/xml/listakanalow-plusbogaty.xml", name: "Bogaty" },
];

const DB_PATH =
  process.env.FUZ_DB_PATH || path.join(process.cwd(), "src", "data", "ServicesRange.db");

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;
}

function getDb() {
  const db = new Database(DB_PATH);
  db.pragma("journal_mode = WAL");
  return db;
}

async function fetchXml(url) {
  const res = await fetch(url, { headers: { accept: "application/xml,text/xml,*/*" } });
  if (!res.ok) throw new Error(`XML HTTP ${res.status} for ${url}`);
  return await res.text();
}

function parseNodes(xmlText) {
  const parser = new XMLParser({
    ignoreAttributes: false,
    attributeNamePrefix: "@_",
  });
  const json = parser.parse(xmlText);
  const nodes = json?.xml?.node ?? json?.node ?? [];
  return Array.isArray(nodes) ? nodes : [nodes];
}

function decodeEntities(input) {
  if (!input) return "";
  let s = String(input)
    .replace(/&nbsp;/g, " ")
    .replace(/&ndash;/g, "–")
    .replace(/&quot;/g, '"')
    .replace(/&apos;/g, "'")
    .replace(/&#39;/g, "'")
    .replace(/&amp;/g, "&")
    .replace(/&lt;/g, "<")
    .replace(/&gt;/g, ">");
  s = s.replace(/&#(\d+);/g, (_, d) => String.fromCodePoint(Number(d)));
  s = s.replace(/&#x([0-9a-fA-F]+);/g, (_, h) => String.fromCodePoint(parseInt(h, 16)));
  return s;
}

function htmlToMarkdown(input) {
  if (!input) return "";

  let html = "";
  if (typeof input === "string") html = input;
  else if (input?.p) {
    if (typeof input.p === "string") html = `<p>${input.p}</p>`;
    else if (Array.isArray(input.p)) html = input.p.map((p) => `<p>${p}</p>`).join("");
  } else html = String(input);

  let s = decodeEntities(html);

  s = s
    .replace(/<\s*(ul|ol)[^>]*>/gi, "\n__LIST_START__\n")
    .replace(/<\/\s*(ul|ol)\s*>/gi, "\n__LIST_END__\n")
    .replace(/<\s*li[^>]*>/gi, "__LI__")
    .replace(/<\/\s*li\s*>/gi, "\n")
    .replace(/<\s*br\s*\/?\s*>/gi, "\n")
    .replace(/<\/\s*(p|div)\s*>/gi, "\n")
    .replace(/<\s*(p|div)[^>]*>/gi, "")
    .replace(/<[^>]+>/g, "")
    .replace(/\r/g, "")
    .replace(/[ \t]+\n/g, "\n")
    .replace(/\n{3,}/g, "\n\n")
    .trim();

  const lines = s.split("\n").map((x) => x.trim());
  const out = [];
  let inList = false;

  for (const line of lines) {
    if (!line) {
      if (!inList) out.push("");
      continue;
    }
    if (line === "__LIST_START__") {
      inList = true;
      continue;
    }
    if (line === "__LIST_END__") {
      inList = false;
      out.push("");
      continue;
    }
    if (inList && line.startsWith("__LI__")) {
      out.push(`- ${line.replace("__LI__", "").trim()}`);
      continue;
    }
    out.push(line);
  }

  return out.join("\n").trim();
}

function extractLogoUrl(node) {
  const logo = node?.field_logo_fid;
  if (!logo) return null;
  if (typeof logo === "string") {
    const m = logo.match(/src="([^"]+)"/);
    return m?.[1] ?? null;
  }
  if (logo?.img?.["@_src"]) return logo.img["@_src"];
  return null;
}

async function downloadLogoAsBase64(url) {
  try {
    const res = await fetch(url);
    if (!res.ok) return null;
    const ct = res.headers.get("content-type") || "image/png";
    const buf = Buffer.from(await res.arrayBuffer());
    if (!buf.length) return null;
    return `data:${ct};base64,${buf.toString("base64")}`;
  } catch {
    return null;
  }
}

export async function POST({ request }) {
  if (!isAuthorized(request)) {
    return new Response(JSON.stringify({ ok: false, error: "Unauthorized" }), {
      status: 401,
      headers: { "content-type": "application/json; charset=utf-8" },
    });
  }

  const db = getDb();

  const upsert = db.prepare(`
    INSERT INTO jambox_channels (nazwa, pckg_name, image, opis)
    VALUES (@nazwa, @pckg_name, @image, @opis)
    ON CONFLICT(nazwa, pckg_name) DO UPDATE SET
      image = COALESCE(excluded.image, jambox_channels.image),
      opis  = COALESCE(excluded.opis,  jambox_channels.opis)
  `);

  const logoCache = new Map();
  const rows = [];

  try {
    for (const feed of FEEDS) {
      const xml = await fetchXml(feed.url);
      const nodes = parseNodes(xml);

      for (const node of nodes) {
        const name = (node?.nazwa_kanalu ?? node?.nazwa ?? "").trim();
        if (!name) continue;

        const opis = htmlToMarkdown(node?.opis) || null;

        const key = name.toLowerCase();
        let img = logoCache.get(key);
        if (img === undefined) {
          const logoUrl = extractLogoUrl(node);
          img = logoUrl ? await downloadLogoAsBase64(logoUrl) : null;
          logoCache.set(key, img);
        }

        rows.push({
          nazwa: name,
          pckg_name: feed.name,
          image: img,
          opis,
        });
      }
    }

    const trx = db.transaction((data) => {
      for (const r of data) upsert.run(r);
    });

    trx(rows);

    return new Response(JSON.stringify({ ok: true, rows: rows.length, db: DB_PATH }), {
      headers: { "content-type": "application/json; charset=utf-8" },
    });
  } catch (e) {
    console.error("import jambox_channels:", e);
    return new Response(JSON.stringify({ ok: false, error: String(e?.message || e) }), {
      status: 500,
      headers: { "content-type": "application/json; charset=utf-8" },
    });
  } finally {
    try { db.close(); } catch {}
  }
}
