const { db } = require("../db/db-connect");
const logger = require("../utils/logger");
const numeral = require("numeral");

require("numeral/locales/fr");
numeral.locale("fr");

async function getRecordIdFromFieldValue(collection, field, value) {
  try {
    const resultList = await db.records.getList(collection, 1, 1, {
      filter: `${field} = '${value}'`,
    });

    if (resultList.totalItems > 0) {
      return resultList.items[0].id;
    } else {
      return null;
    }
  } catch (error) {
    logger.log("error", error);
    return null;
  }
}

async function fetchInfoByCriteria(collection, criteria) {
  try {
    const resultList = await db.records.getList(collection, 1, 1, criteria);

    if (resultList.totalItems > 0) {
      return resultList.items[0];
    }
  } catch (error) {
    /**
     * Gestion silencieuse des erreurs d'abort (requêtes interrompues)
     * Ces erreurs sont normales lors de requêtes parallèles et ne doivent pas être loggées
     */
    if (error?.isAbort || error?.name?.includes("Abort") || error?.status === 0) {
      return null;
    }
    // Autres erreurs loggées en info (pas en error) pour éviter le bruit dans les logs
    logger.log("info", `Erreur récupération ${collection}:`, error?.message || error);
  }

  return null;
}

async function updateRecordFromData(collection, recordID, data) {
  try {
    const record = await db.records.update(collection, recordID, data);

    return record;
  } catch (error) {
    logger.log("error", error);
  }

  return null;
}

function customFormatNumber(number, decimal, taux=false) {
  if (Number.isInteger(number)) {
    if (decimal == true) {
      return numeral(number).format("0,0.00");
    } else {
      return numeral(number).format("0,0");
    }
  } else {
    if (taux == true) {
      return numeral(number).format("0,0.000");
    } else {
      return numeral(number).format("0,0.00");
    }
  }
}

function cleanDoubleSpaces(inputString) {
  return inputString.replace(/\s{2,}/g, " ");
}

/**
 * Formate une date ISO en format français (jj/mm/aaaa)
 * @param {string|Date} iso - Date au format ISO
 * @param {boolean} withTime - Inclure l'heure (défaut: false)
 * @returns {string} Date formatée (dd/mm/yyyy ou dd/mm/yyyy hh:mm)
 */
function fmtDateFR(iso, withTime = false) {
  if (!iso) return "NC";
  
  const d = new Date(iso);
  if (isNaN(d.getTime())) return "NC";
  
  const dd = String(d.getDate()).padStart(2, "0");
  const mm = String(d.getMonth() + 1).padStart(2, "0");
  const yyyy = d.getFullYear();
  
  if (!withTime) {
    return `${dd}/${mm}/${yyyy}`;
  }
  
  const hh = String(d.getHours()).padStart(2, "0");
  const mi = String(d.getMinutes()).padStart(2, "0");
  return `${dd}/${mm}/${yyyy} ${hh}:${mi}`;
}

/**
 * Échappe les caractères spéciaux XML
 * @param {string} s - Chaîne à échapper
 * @returns {string} Chaîne échappée
 */
function xmlEsc(s) {
  return String(s ?? "")
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&apos;");
}

/**
 * Génère une cellule XML pour Excel
 * @param {string} v - Valeur de la cellule
 * @returns {string} Cellule XML formatée
 */
function cellXml(v) {
  return `<Cell><Data ss:Type="String">${xmlEsc(v)}</Data></Cell>`;
}

/**
 * Génère une ligne XML pour Excel
 * @param {Array<string>} cells - Tableau de valeurs pour les cellules
 * @returns {string} Ligne XML formatée
 */
function rowXml(cells) {
  return `<Row>${cells.map(cellXml).join("")}</Row>`;
}

module.exports = {
  getRecordIdFromFieldValue,
  fetchInfoByCriteria,
  updateRecordFromData,
  cleanDoubleSpaces,
  customFormatNumber,
  fmtDateFR,
  xmlEsc,
  cellXml,
  rowXml,
};
