const crypto = require("crypto");
const sanitizeHtml = require("sanitize-html");
const slugify = require("slugify");

function escapeHtml(value = "") {
  return String(value)
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#039;");
}

function cleanRichText(value = "") {
  return sanitizeHtml(String(value), {
    allowedTags: ["p", "br", "strong", "b", "em", "i", "h2", "h3", "h4", "ul", "ol", "li", "a"],
    allowedAttributes: {
      a: ["href", "target", "rel"]
    },
    allowedSchemes: ["http", "https", "mailto", "tel"],
    transformTags: {
      a: (tagName, attribs) => ({
        tagName,
        attribs: {
          href: attribs.href || "#",
          target: attribs.target === "_blank" ? "_blank" : undefined,
          rel: attribs.target === "_blank" ? "noopener noreferrer" : undefined
        }
      })
    }
  });
}

function makeSlug(value, fallback = "entry") {
  const slug = slugify(String(value || ""), { lower: true, strict: true, trim: true });
  return slug || `${fallback}-${Date.now()}`;
}

function token(size = 24) {
  return crypto.randomBytes(size).toString("hex");
}

function now() {
  return new Date().toISOString();
}

function bytes(n = 0) {
  if (n < 1024) return `${n} B`;
  if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
  if (n < 1024 * 1024 * 1024) return `${(n / 1024 / 1024).toFixed(1)} MB`;
  return `${(n / 1024 / 1024 / 1024).toFixed(1)} GB`;
}

function checkbox(value) {
  return value ? 1 : 0;
}

function listFromText(value = "") {
  return String(value)
    .split(/\r?\n|,/)
    .map((part) => part.trim())
    .filter(Boolean);
}

function safeJson(value, fallback = {}) {
  if (!value) return fallback;
  try {
    return JSON.parse(value);
  } catch {
    return fallback;
  }
}

function safeCssColor(value, fallback = "#000000") {
  const text = String(value || "").trim();
  if (/^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$/.test(text)) return text;
  if (/^rgba?\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}(\s*,\s*(0|1|0?\.\d+))?\s*\)$/.test(text)) return text;
  return fallback;
}

function safeCssNumber(value, fallback = 0, min = 0, max = 1) {
  const number = Number(value);
  if (!Number.isFinite(number)) return fallback;
  return Math.min(max, Math.max(min, number));
}

function safeCssKeyword(value, allowed, fallback) {
  const text = String(value || "").trim().toLowerCase();
  return allowed.includes(text) ? text : fallback;
}

function safeCssUrl(value) {
  const text = String(value || "").trim();
  if (!text) return "";
  if (/^\/[A-Za-z0-9/_\-.%]+$/.test(text)) return text;
  if (/^https:\/\/[^\s"'()<>]+$/i.test(text)) return text;
  return "";
}

module.exports = {
  escapeHtml,
  cleanRichText,
  makeSlug,
  token,
  now,
  bytes,
  checkbox,
  listFromText,
  safeJson,
  safeCssColor,
  safeCssNumber,
  safeCssKeyword,
  safeCssUrl
};
