import { pool } from "../db/pool.js";
import { ApiError } from "../utils/ApiError.js";

const cleanString = (value) => String(value ?? "").trim();
const toNumber = (value, fallback = 0) => {
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : fallback;
};

export const MGX_REFERENCE_CATEGORIES = [
  "vehicle_category",
  "vehicle_status",
  "fuel_type",
  "kilometer_type",
  "maintenance_type",
  "intervention_status",
  "document_type",
  "purchase_category",
  "consumable_category",
  "unit_of_measure",
  "purchase_status",
  "supplier_type",
  "service_type",
  "payment_method",
  "expense_type",
  "rental_status",
  "alert_type",
  "it_asset_type",
  "it_asset_status",
];

const DEFAULT_ENABLED_MODULES = {
  fuel: true,
  maintenance: true,
  purchases: true,
  consumables: true,
  services: true,
  rentals: true,
  treasury: true,
  it_assets: true,
  alerts: true,
  reporting: true,
};

const REFERENCE_USAGE_QUERIES = [
  ["mgx_vehicles", "category_ref_id"],
  ["mgx_vehicles", "fuel_type_ref_id"],
  ["mgx_vehicles", "status_ref_id"],
  ["mgx_it_assets", "type_ref_id"],
  ["mgx_it_assets", "status_ref_id"],
  ["mgx_vehicle_km_history", "reading_type_ref_id"],
  ["mgx_vehicle_documents", "document_type_ref_id"],
  ["mgx_fuel_entries", "fuel_type_ref_id"],
  ["mgx_maintenance_plans", "maintenance_type_ref_id"],
  ["mgx_interventions", "maintenance_type_ref_id"],
  ["mgx_interventions", "status_ref_id"],
  ["mgx_suppliers", "supplier_type_ref_id"],
  ["mgx_suppliers", "payment_method_ref_id"],
  ["mgx_purchase_requests", "category_ref_id"],
  ["mgx_purchase_request_lines", "unit_ref_id"],
  ["mgx_purchase_orders", "category_ref_id"],
  ["mgx_purchase_orders", "status_ref_id"],
  ["mgx_purchase_order_lines", "unit_ref_id"],
  ["mgx_services", "service_type_ref_id"],
  ["mgx_rentals", "status_ref_id"],
  ["mgx_consumable_items", "category_ref_id"],
  ["mgx_consumable_items", "unit_ref_id"],
  ["mgx_treasury_movements", "expense_type_ref_id"],
  ["mgx_treasury_movements", "payment_method_ref_id"],
  ["mgx_alert_configs", "alert_type_ref_id"],
];

const CATEGORY_SEEDS = {
  vehicle_category: [
    ["CAM", "Camion", "#2563EB", "Truck"],
    ["UTIL", "Véhicule utilitaire", "#0891B2", "Truck"],
    ["LIAISON", "Voiture de liaison", "#10B981", "Car"],
  ],
  vehicle_status: [
    ["ACTIVE", "Actif", "#10B981", "CircleCheck"],
    ["PANNE", "En panne", "#EF4444", "TriangleAlert"],
    ["MAINT", "En maintenance", "#F59E0B", "Wrench"],
    ["CEDE", "Cédé", "#64748B", "Archive"],
  ],
  it_asset_type: [
    ["PC", "Ordinateur", "#2563EB", "Laptop"],
    ["PHONE", "Téléphone", "#10B981", "Smartphone"],
    ["PRINTER", "Imprimante", "#F59E0B", "Printer"],
    ["NETWORK", "Réseau", "#06B6D4", "Router"],
    ["OTHER", "Autre matériel", "#64748B", "Package"],
  ],
  it_asset_status: [
    ["ACTIVE", "En service", "#10B981", "CircleCheck"],
    ["STOCK", "En stock", "#3B82F6", "Package"],
    ["REPAIR", "En réparation", "#F59E0B", "Wrench"],
    ["REFORM", "Réformé", "#64748B", "Archive"],
    ["LOST", "Perdu", "#EF4444", "CircleX"],
  ],
  fuel_type: [
    ["GO", "Gasoil", "#F59E0B", "Fuel", { unit: "Litre" }],
    ["ESS", "Essence sans plomb", "#10B981", "Fuel", { unit: "Litre" }],
    ["GPL", "GPL", "#3B82F6", "Fuel", { unit: "Litre" }],
  ],
  kilometer_type: [
    ["REAL", "Réel", "#10B981", "Gauge"],
    ["EST", "Estimé", "#F59E0B", "Gauge"],
    ["TEL", "Télématique", "#3B82F6", "Satellite"],
  ],
  maintenance_type: [
    ["VID", "Vidange", "#3B82F6", "Wrench", { frequency_km: 10000, frequency_days: 180 }],
    ["REV", "Révision périodique", "#10B981", "CalendarCheck", { frequency_km: 20000, frequency_days: 365 }],
    ["PNEU", "Changement pneus", "#F59E0B", "Circle", { frequency_km: 40000 }],
  ],
  intervention_status: [
    ["OPEN", "En cours", "#3B82F6", "Clock"],
    ["DONE", "Terminé", "#10B981", "CircleCheck"],
    ["WAIT", "En attente pièces", "#F59E0B", "Package"],
    ["CANCEL", "Annulé", "#EF4444", "CircleX"],
  ],
  document_type: [
    ["ASS", "Assurance", "#3B82F6", "ShieldCheck", { alert_days: 30 }],
    ["CT", "Contrôle technique", "#F59E0B", "FileCheck", { alert_days: 30 }],
    ["CG", "Carte grise", "#64748B", "IdCard", { alert_days: 60 }],
  ],
  purchase_category: [
    ["PDR", "Pièces de rechange", "#3B82F6", "Package"],
    ["LUB", "Lubrifiants", "#F59E0B", "Droplets"],
    ["EPI", "EPI", "#10B981", "Shield"],
  ],
  consumable_category: [
    ["DET", "Détergents", "#06B6D4", "Sparkles"],
    ["BUR", "Bureautique", "#3B82F6", "Paperclip"],
    ["LUB", "Lubrifiants", "#F59E0B", "Droplets"],
  ],
  unit_of_measure: [
    ["L", "Litre", "#3B82F6", "Ruler", { symbol: "L" }],
    ["PCS", "Pièce", "#10B981", "Hash", { symbol: "pcs" }],
    ["KG", "Kilogramme", "#F59E0B", "Scale", { symbol: "kg" }],
  ],
  purchase_status: [
    ["DRAFT", "Brouillon", "#F59E0B", "FileText"],
    ["VALID", "Validée", "#10B981", "CheckSquare"],
    ["ORDERED", "Commandée", "#3B82F6", "ClipboardList"],
    ["RECEIVED", "Reçue", "#10B981", "PackageCheck"],
    ["CANCEL", "Annulée", "#EF4444", "CircleX"],
  ],
  supplier_type: [
    ["MAT", "Fournisseur matériaux", "#3B82F6", "Building2"],
    ["PREST", "Prestataire", "#10B981", "Handshake"],
    ["LOUEUR", "Loueur", "#F59E0B", "Truck"],
    ["STATION", "Station-service", "#EF4444", "Fuel"],
  ],
  service_type: [
    ["MECA", "Mécanique", "#3B82F6", "Wrench"],
    ["TOL", "Tôlerie", "#F59E0B", "Hammer"],
    ["LAV", "Lavage", "#06B6D4", "Sparkles"],
    ["FRIGO", "Groupe frigorifique", "#10B981", "Snowflake"],
  ],
  payment_method: [
    ["VIR", "Virement", "#3B82F6", "Landmark"],
    ["CHQ", "Chèque", "#10B981", "Receipt"],
    ["ESP", "Espèces", "#F59E0B", "Wallet"],
  ],
  expense_type: [
    ["FUEL", "Carburant", "#F59E0B", "Fuel"],
    ["MAINT", "Maintenance", "#3B82F6", "Wrench"],
    ["RENT", "Location", "#10B981", "Truck"],
    ["OTHER", "Autre", "#64748B", "MoreHorizontal"],
  ],
  rental_status: [
    ["ACTIVE", "Active", "#10B981", "CircleCheck"],
    ["DONE", "Terminée", "#64748B", "Archive"],
    ["CANCEL", "Résiliée", "#EF4444", "CircleX"],
  ],
  alert_type: [
    ["ASS_EXP", "Assurance expirante", "#EF4444", "Bell"],
    ["CT_EXP", "Contrôle technique", "#F59E0B", "Bell"],
    ["MAINT_DUE", "Entretien préventif", "#3B82F6", "Wrench"],
    ["STOCK_MIN", "Stock minimum", "#EF4444", "Archive"],
  ],
};

const getCompanyId = (req) => {
  const companyId = Number(req.query.company_id || req.body.company_id || req.user?.companyId);

  if (!companyId) {
    throw new ApiError(400, "Société requise.");
  }

  return companyId;
};

const logMgxAudit = async (db, req, { companyId, action, entityType, entityId, oldData, newData }) => {
  await db.query(
    `
      INSERT INTO mgx_audit_log (
        company_id,
        user_id,
        action,
        entity_type,
        entity_id,
        old_data,
        new_data,
        ip_address
      )
      VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
    `,
    [
      companyId,
      req.user?.sub || null,
      action,
      entityType,
      entityId,
      oldData ? JSON.stringify(oldData) : null,
      newData ? JSON.stringify(newData) : null,
      req.ip,
    ],
  );
};

const mapDepot = (row) => ({
  id: Number(row.id),
  company_id: Number(row.company_id),
  company: row.company_name ? { id: Number(row.company_id), name: row.company_name } : null,
  code: row.code,
  label: row.label,
  address: row.address,
  city: row.city,
  phone: row.phone,
  manager_name: row.manager_name,
  vehicles_count: Number(row.vehicles_count || 0),
  movements_count: Number(row.movements_count || 0),
  is_active: row.is_active,
  created_at: row.created_at,
  updated_at: row.updated_at,
});

const mapReferentiel = (row) => ({
  id: Number(row.id),
  company_id: Number(row.company_id),
  category: row.category,
  code: row.code,
  label: row.label,
  description: row.description,
  color: row.color,
  icon: row.icon,
  sort_order: Number(row.sort_order || 0),
  metadata: row.metadata || {},
  is_active: row.is_active,
  usage_count: Number(row.usage_count || 0),
  created_at: row.created_at,
  updated_at: row.updated_at,
});

const fetchReferentielById = async (db, id) => {
  const { rows } = await db.query(
    `
      SELECT *
      FROM mgx_referentiels
      WHERE id = $1
      LIMIT 1
    `,
    [id],
  );

  return rows[0] ? mapReferentiel(rows[0]) : null;
};

const fetchReferenceUsageCount = async (db, referenceId) => {
  let count = 0;

  for (const [table, column] of REFERENCE_USAGE_QUERIES) {
    const { rows } = await db.query(
      `SELECT COUNT(*)::int AS count FROM ${table} WHERE ${column} = $1`,
      [referenceId],
    );
    count += Number(rows[0]?.count || 0);
  }

  return count;
};

const ensureSettings = async (db, companyId) => {
  const { rows } = await db.query(
    `
      INSERT INTO mgx_settings (company_id)
      VALUES ($1)
      ON CONFLICT (company_id) DO UPDATE
      SET company_id = EXCLUDED.company_id
      RETURNING *
    `,
    [companyId],
  );

  return {
    id: Number(rows[0].id),
    company_id: Number(rows[0].company_id),
    default_currency: rows[0].default_currency,
    date_format: rows[0].date_format,
    fuel_anomaly_threshold_pct: Number(rows[0].fuel_anomaly_threshold_pct || 0),
    default_alert_days_by_document_type: rows[0].default_alert_days_by_document_type || {},
    default_payment_terms: Number(rows[0].default_payment_terms || 0),
    enabled_modules: rows[0].enabled_modules || DEFAULT_ENABLED_MODULES,
  };
};

export const mgxAdminController = {
  getSettings: async (req, res) => {
    const client = await pool.connect();

    try {
      const companyId = getCompanyId(req);
      const settings = await ensureSettings(client, companyId);
      res.json({ item: settings });
    } finally {
      client.release();
    }
  },

  updateSettings: async (req, res) => {
    const client = await pool.connect();

    try {
      await client.query("BEGIN");
      const companyId = getCompanyId(req);
      const previous = await ensureSettings(client, companyId);
      const enabledModules = {
        ...DEFAULT_ENABLED_MODULES,
        ...(req.body.enabled_modules || req.body.enabledModules || {}),
      };

      const { rows } = await client.query(
        `
          UPDATE mgx_settings
          SET
            default_currency = $2,
            date_format = $3,
            fuel_anomaly_threshold_pct = $4,
            default_alert_days_by_document_type = $5,
            default_payment_terms = $6,
            enabled_modules = $7,
            updated_at = CURRENT_TIMESTAMP
          WHERE company_id = $1
          RETURNING *
        `,
        [
          companyId,
          cleanString(req.body.default_currency || req.body.defaultCurrency || "DZD") || "DZD",
          cleanString(req.body.date_format || req.body.dateFormat || "DD/MM/YYYY") || "DD/MM/YYYY",
          toNumber(req.body.fuel_anomaly_threshold_pct ?? req.body.fuelAnomalyThresholdPct, 30),
          JSON.stringify(
            req.body.default_alert_days_by_document_type ||
              req.body.defaultAlertDaysByDocumentType ||
              {},
          ),
          toNumber(req.body.default_payment_terms ?? req.body.defaultPaymentTerms, 30),
          JSON.stringify(enabledModules),
        ],
      );

      const item = await ensureSettings(client, companyId);

      await logMgxAudit(client, req, {
        companyId,
        action: "settings.update",
        entityType: "mgx_settings",
        entityId: rows[0].id,
        oldData: previous,
        newData: item,
      });

      await client.query("COMMIT");
      res.json({ message: "Paramètres MGX mis à jour.", item });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },

  listDepots: async (req, res) => {
    const allCompanies = req.query.all_companies === "true" || req.query.company_id === "all";
    const companyId = allCompanies ? null : getCompanyId(req);
    const { rows } = await pool.query(
      `
        SELECT
          d.*,
          c.name AS company_name,
          COUNT(DISTINCT v.id)::int AS vehicles_count,
          (
            COUNT(DISTINCT f.id) +
            COUNT(DISTINCT i.id) +
            COUNT(DISTINCT pr.id) +
            COUNT(DISTINCT po.id) +
            COUNT(DISTINCT r.id) +
            COUNT(DISTINCT s.id) +
            COUNT(DISTINCT cm.id) +
            COUNT(DISTINCT tm.id)
          )::int AS movements_count
        FROM mgx_depots d
        LEFT JOIN companies c ON c.id = d.company_id
        LEFT JOIN mgx_vehicles v ON v.depot_id = d.id
        LEFT JOIN mgx_fuel_entries f ON f.depot_id = d.id
        LEFT JOIN mgx_interventions i ON i.depot_id = d.id
        LEFT JOIN mgx_purchase_requests pr ON pr.depot_id = d.id
        LEFT JOIN mgx_purchase_orders po ON po.depot_id = d.id
        LEFT JOIN mgx_receptions r ON r.depot_id = d.id
        LEFT JOIN mgx_services s ON s.depot_id = d.id
        LEFT JOIN mgx_consumable_movements cm ON cm.depot_id = d.id
        LEFT JOIN mgx_treasury_movements tm ON tm.depot_id = d.id
        ${allCompanies ? "" : "WHERE d.company_id = $1"}
        GROUP BY d.id, c.name
        ORDER BY c.name ASC, d.is_active DESC, d.code ASC
      `,
      allCompanies ? [] : [companyId],
    );

    res.json({ items: rows.map(mapDepot) });
  },

  createDepot: async (req, res) => {
    const client = await pool.connect();

    try {
      await client.query("BEGIN");
      const companyId = getCompanyId(req);
      const code = cleanString(req.body.code).toUpperCase();
      const label = cleanString(req.body.label);

      if (!code || !label) {
        throw new ApiError(400, "Le code et le libellé sont obligatoires.");
      }

      const { rows } = await client.query(
        `
          INSERT INTO mgx_depots (
            company_id, code, label, address, city, phone, manager_name, is_active
          )
          VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
          RETURNING *, 0::int AS vehicles_count, 0::int AS movements_count
        `,
        [
          companyId,
          code,
          label,
          cleanString(req.body.address) || null,
          cleanString(req.body.city) || null,
          cleanString(req.body.phone) || null,
          cleanString(req.body.manager_name || req.body.managerName) || null,
          req.body.is_active !== false,
        ],
      );

      const item = mapDepot(rows[0]);
      await logMgxAudit(client, req, {
        companyId,
        action: "depots.create",
        entityType: "mgx_depots",
        entityId: item.id,
        newData: item,
      });

      await client.query("COMMIT");
      res.status(201).json({ message: "Dépôt créé.", item });
    } catch (error) {
      await client.query("ROLLBACK");
      if (error.code === "23505") {
        throw new ApiError(409, "Ce code dépôt existe déjà.");
      }
      throw error;
    } finally {
      client.release();
    }
  },

  updateDepot: async (req, res) => {
    const client = await pool.connect();

    try {
      await client.query("BEGIN");
      const companyId = getCompanyId(req);
      const depotId = Number(req.params.id);
      const { rows: previousRows } = await client.query(
        "SELECT *, 0::int AS vehicles_count, 0::int AS movements_count FROM mgx_depots WHERE id = $1 AND company_id = $2",
        [depotId, companyId],
      );

      if (!previousRows[0]) {
        throw new ApiError(404, "Dépôt introuvable.");
      }

      const { rows } = await client.query(
        `
          UPDATE mgx_depots
          SET
            code = $3,
            label = $4,
            address = $5,
            city = $6,
            phone = $7,
            manager_name = $8,
            is_active = $9,
            updated_at = CURRENT_TIMESTAMP
          WHERE id = $1 AND company_id = $2
          RETURNING *, 0::int AS vehicles_count, 0::int AS movements_count
        `,
        [
          depotId,
          companyId,
          cleanString(req.body.code || previousRows[0].code).toUpperCase(),
          cleanString(req.body.label || previousRows[0].label),
          cleanString(req.body.address) || null,
          cleanString(req.body.city) || null,
          cleanString(req.body.phone) || null,
          cleanString(req.body.manager_name || req.body.managerName) || null,
          req.body.is_active === undefined ? previousRows[0].is_active : Boolean(req.body.is_active),
        ],
      );

      const item = mapDepot(rows[0]);
      await logMgxAudit(client, req, {
        companyId,
        action: "depots.update",
        entityType: "mgx_depots",
        entityId: item.id,
        oldData: mapDepot(previousRows[0]),
        newData: item,
      });

      await client.query("COMMIT");
      res.json({ message: "Dépôt mis à jour.", item });
    } catch (error) {
      await client.query("ROLLBACK");
      if (error.code === "23505") {
        throw new ApiError(409, "Ce code dépôt existe déjà.");
      }
      throw error;
    } finally {
      client.release();
    }
  },

  deleteDepot: async (req, res) => {
    const client = await pool.connect();

    try {
      await client.query("BEGIN");
      const companyId = getCompanyId(req);
      const depotId = Number(req.params.id);
      const { rows } = await client.query(
        "SELECT *, 0::int AS vehicles_count, 0::int AS movements_count FROM mgx_depots WHERE id = $1 AND company_id = $2",
        [depotId, companyId],
      );

      if (!rows[0]) {
        throw new ApiError(404, "Dépôt introuvable.");
      }

      const usageQueries = [
        ["mgx_vehicles", "depot_id"],
        ["mgx_fuel_entries", "depot_id"],
        ["mgx_interventions", "depot_id"],
        ["mgx_purchase_requests", "depot_id"],
        ["mgx_purchase_orders", "depot_id"],
        ["mgx_receptions", "depot_id"],
        ["mgx_services", "depot_id"],
        ["mgx_consumable_movements", "depot_id"],
        ["mgx_treasury_movements", "depot_id"],
      ];
      let usageCount = 0;

      for (const [table, column] of usageQueries) {
        const result = await client.query(
          `SELECT COUNT(*)::int AS count FROM ${table} WHERE ${column} = $1`,
          [depotId],
        );
        usageCount += Number(result.rows[0]?.count || 0);
      }

      if (usageCount > 0) {
        throw new ApiError(409, "Impossible de supprimer un dépôt déjà utilisé.");
      }

      await client.query("DELETE FROM mgx_depots WHERE id = $1", [depotId]);
      await logMgxAudit(client, req, {
        companyId,
        action: "depots.delete",
        entityType: "mgx_depots",
        entityId: depotId,
        oldData: mapDepot(rows[0]),
      });

      await client.query("COMMIT");
      res.json({ message: "Dépôt supprimé." });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },

  listReferentiels: async (req, res) => {
    const companyId = getCompanyId(req);
    const category = cleanString(req.query.category);
    const showInactive = req.query.active === "false" || req.query.include_inactive === "true";

    const params = [companyId];
    const filters = ["r.company_id = $1"];

    if (category) {
      params.push(category);
      filters.push(`r.category = $${params.length}`);
    }

    if (!showInactive) {
      filters.push("r.is_active = TRUE");
    }

    const { rows } = await pool.query(
      `
        SELECT r.*
        FROM mgx_referentiels r
        WHERE ${filters.join(" AND ")}
        ORDER BY r.category ASC, r.sort_order ASC, r.label ASC
      `,
      params,
    );

    res.json({ items: rows.map(mapReferentiel), categories: MGX_REFERENCE_CATEGORIES });
  },

  listAllReferentiels: async (req, res) => {
    const companyId = getCompanyId(req);
    const { rows } = await pool.query(
      `
        SELECT *
        FROM mgx_referentiels
        WHERE company_id = $1
        ORDER BY category ASC, sort_order ASC, label ASC
      `,
      [companyId],
    );
    const grouped = {};

    for (const row of rows.map(mapReferentiel)) {
      grouped[row.category] ||= [];
      grouped[row.category].push(row);
    }

    res.json({ items: grouped, categories: MGX_REFERENCE_CATEGORIES });
  },

  createReferentiel: async (req, res) => {
    const client = await pool.connect();

    try {
      await client.query("BEGIN");
      const companyId = getCompanyId(req);
      const category = cleanString(req.body.category);
      const label = cleanString(req.body.label);

      if (!MGX_REFERENCE_CATEGORIES.includes(category)) {
        throw new ApiError(400, "Catégorie de référentiel invalide.");
      }

      if (!label) {
        throw new ApiError(400, "Le libellé est obligatoire.");
      }

      const { rows } = await client.query(
        `
          INSERT INTO mgx_referentiels (
            company_id, category, code, label, description, color, icon,
            sort_order, metadata, is_active
          )
          VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
          RETURNING *
        `,
        [
          companyId,
          category,
          cleanString(req.body.code).toUpperCase() || null,
          label,
          cleanString(req.body.description) || null,
          cleanString(req.body.color) || null,
          cleanString(req.body.icon) || null,
          toNumber(req.body.sort_order ?? req.body.sortOrder, 0),
          JSON.stringify(req.body.metadata || {}),
          req.body.is_active !== false,
        ],
      );

      const item = mapReferentiel(rows[0]);
      await logMgxAudit(client, req, {
        companyId,
        action: "referentiels.create",
        entityType: "mgx_referentiels",
        entityId: item.id,
        newData: item,
      });

      await client.query("COMMIT");
      res.status(201).json({ message: "Référentiel créé.", item });
    } catch (error) {
      await client.query("ROLLBACK");
      if (error.code === "23505") {
        throw new ApiError(409, "Ce code existe déjà dans cette catégorie.");
      }
      throw error;
    } finally {
      client.release();
    }
  },

  updateReferentiel: async (req, res) => {
    const client = await pool.connect();

    try {
      await client.query("BEGIN");
      const companyId = getCompanyId(req);
      const referenceId = Number(req.params.id);
      const previous = await fetchReferentielById(client, referenceId);

      if (!previous || previous.company_id !== companyId) {
        throw new ApiError(404, "Élément introuvable.");
      }

      const { rows } = await client.query(
        `
          UPDATE mgx_referentiels
          SET
            code = $3,
            label = $4,
            description = $5,
            color = $6,
            icon = $7,
            sort_order = $8,
            metadata = $9,
            is_active = $10,
            updated_at = CURRENT_TIMESTAMP
          WHERE id = $1 AND company_id = $2
          RETURNING *
        `,
        [
          referenceId,
          companyId,
          cleanString(req.body.code ?? previous.code).toUpperCase() || null,
          cleanString(req.body.label ?? previous.label),
          cleanString(req.body.description ?? previous.description) || null,
          cleanString(req.body.color ?? previous.color) || null,
          cleanString(req.body.icon ?? previous.icon) || null,
          toNumber(req.body.sort_order ?? req.body.sortOrder, previous.sort_order),
          JSON.stringify(req.body.metadata ?? previous.metadata ?? {}),
          req.body.is_active === undefined ? previous.is_active : Boolean(req.body.is_active),
        ],
      );

      const item = mapReferentiel(rows[0]);
      await logMgxAudit(client, req, {
        companyId,
        action: "referentiels.update",
        entityType: "mgx_referentiels",
        entityId: item.id,
        oldData: previous,
        newData: item,
      });

      await client.query("COMMIT");
      res.json({ message: "Référentiel mis à jour.", item });
    } catch (error) {
      await client.query("ROLLBACK");
      if (error.code === "23505") {
        throw new ApiError(409, "Ce code existe déjà dans cette catégorie.");
      }
      throw error;
    } finally {
      client.release();
    }
  },

  deleteReferentiel: async (req, res) => {
    const client = await pool.connect();

    try {
      await client.query("BEGIN");
      const companyId = getCompanyId(req);
      const referenceId = Number(req.params.id);
      const previous = await fetchReferentielById(client, referenceId);

      if (!previous || previous.company_id !== companyId) {
        throw new ApiError(404, "Élément introuvable.");
      }

      const usageCount = await fetchReferenceUsageCount(client, referenceId);

      if (usageCount > 0) {
        throw new ApiError(409, `Suppression impossible: ${usageCount} référence(s) existante(s).`);
      }

      await client.query("DELETE FROM mgx_referentiels WHERE id = $1", [referenceId]);
      await logMgxAudit(client, req, {
        companyId,
        action: "referentiels.delete",
        entityType: "mgx_referentiels",
        entityId: referenceId,
        oldData: previous,
      });

      await client.query("COMMIT");
      res.json({ message: "Élément supprimé." });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },

  seedReferentielCategory: async (req, res) => {
    const client = await pool.connect();

    try {
      await client.query("BEGIN");
      const companyId = getCompanyId(req);
      const category = cleanString(req.params.category);
      const seeds = CATEGORY_SEEDS[category] || [];

      if (!MGX_REFERENCE_CATEGORIES.includes(category)) {
        throw new ApiError(400, "Catégorie de référentiel invalide.");
      }

      let inserted = 0;

      for (const [code, label, color, icon, metadata = {}] of seeds) {
        const { rowCount } = await client.query(
          `
            INSERT INTO mgx_referentiels (
              company_id, category, code, label, color, icon, metadata, sort_order
            )
            VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
            ON CONFLICT (company_id, category, code) DO NOTHING
          `,
          [companyId, category, code, label, color, icon, JSON.stringify(metadata), inserted + 1],
        );
        inserted += rowCount;
      }

      await logMgxAudit(client, req, {
        companyId,
        action: "referentiels.seed",
        entityType: "mgx_referentiels",
        entityId: null,
        newData: { category, inserted },
      });

      await client.query("COMMIT");
      res.json({ message: "Exemples chargés.", inserted });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },

  getReferentielUsageCount: async (req, res) => {
    const client = await pool.connect();

    try {
      const referenceId = Number(req.params.id);
      const usage_count = await fetchReferenceUsageCount(client, referenceId);
      res.json({ usage_count });
    } finally {
      client.release();
    }
  },

  listAlertConfigs: async (req, res) => {
    const companyId = getCompanyId(req);
    const { rows } = await pool.query(
      `
        SELECT
          ac.*,
          rt.label AS alert_type_label,
          rt.color AS alert_type_color,
          rt.icon AS alert_type_icon,
          COALESCE(active_alerts.active_alerts_count, 0)::int AS active_alerts_count
        FROM mgx_alert_configs ac
        LEFT JOIN mgx_referentiels rt ON rt.id = ac.alert_type_ref_id
        LEFT JOIN (
          SELECT alert_config_id, COUNT(*)::int AS active_alerts_count
          FROM mgx_alerts
          WHERE company_id = $1
            AND status = 'active'
          GROUP BY alert_config_id
        ) active_alerts ON active_alerts.alert_config_id = ac.id
        WHERE ac.company_id = $1
        ORDER BY ac.is_active DESC, ac.criticality DESC, ac.label ASC
      `,
      [companyId],
    );

    res.json({
      items: rows.map((row) => ({
        id: Number(row.id),
        company_id: Number(row.company_id),
        alert_type_ref_id: row.alert_type_ref_id ? Number(row.alert_type_ref_id) : null,
        alert_type_label: row.alert_type_label,
        alert_type_color: row.alert_type_color,
        alert_type_icon: row.alert_type_icon,
        label: row.label,
        trigger_entity: row.trigger_entity,
        trigger_field: row.trigger_field,
        threshold_value: row.threshold_value === null ? null : Number(row.threshold_value),
        threshold_unit: row.threshold_unit,
        criticality: row.criticality,
        is_active: row.is_active,
        active_alerts_count: Number(row.active_alerts_count || 0),
      })),
    });
  },

  saveAlertConfig: async (req, res) => {
    const client = await pool.connect();

    try {
      await client.query("BEGIN");
      const companyId = getCompanyId(req);
      const configId = Number(req.params.id || 0);
      const label = cleanString(req.body.label);

      if (!label) {
        throw new ApiError(400, "Le libellé est obligatoire.");
      }

      const values = [
        companyId,
        req.body.alert_type_ref_id || req.body.alertTypeRefId || null,
        label,
        cleanString(req.body.trigger_entity || req.body.triggerEntity),
        cleanString(req.body.trigger_field || req.body.triggerField),
        req.body.threshold_value ?? req.body.thresholdValue ?? null,
        cleanString(req.body.threshold_unit || req.body.thresholdUnit) || null,
        cleanString(req.body.criticality || "warning"),
        req.body.is_active !== false,
      ];

      const { rows } = configId
        ? await client.query(
            `
              UPDATE mgx_alert_configs
              SET
                alert_type_ref_id = $2,
                label = $3,
                trigger_entity = $4,
                trigger_field = $5,
                threshold_value = $6,
                threshold_unit = $7,
                criticality = $8,
                is_active = $9,
                updated_at = CURRENT_TIMESTAMP
              WHERE id = $10 AND company_id = $1
              RETURNING *
            `,
            [...values, configId],
          )
        : await client.query(
            `
              INSERT INTO mgx_alert_configs (
                company_id,
                alert_type_ref_id,
                label,
                trigger_entity,
                trigger_field,
                threshold_value,
                threshold_unit,
                criticality,
                is_active
              )
              VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
              RETURNING *
            `,
            values,
          );

      if (!rows[0]) {
        throw new ApiError(404, "Configuration d'alerte introuvable.");
      }

      await logMgxAudit(client, req, {
        companyId,
        action: configId ? "alert_configs.update" : "alert_configs.create",
        entityType: "mgx_alert_configs",
        entityId: rows[0].id,
        newData: rows[0],
      });

      await client.query("COMMIT");
      res.status(configId ? 200 : 201).json({
        message: configId ? "Alerte mise à jour." : "Alerte créée.",
        item: rows[0],
      });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },

  testAlertConfigs: async (req, res) => {
    const companyId = getCompanyId(req);
    const { rows } = await pool.query(
      `
        SELECT
          COUNT(*) FILTER (WHERE trigger_entity = 'document')::int AS document_checks,
          COUNT(*) FILTER (WHERE trigger_entity = 'maintenance')::int AS maintenance_checks,
          COUNT(*) FILTER (WHERE trigger_entity = 'rental')::int AS rental_checks,
          COUNT(*) FILTER (WHERE trigger_entity = 'consumable')::int AS consumable_checks
        FROM mgx_alert_configs
        WHERE company_id = $1 AND is_active = TRUE
      `,
      [companyId],
    );

    const stats = rows[0] || {};

    res.json({
      message: "Simulation des alertes terminée.",
      preview: {
        active_configs:
          Number(stats.document_checks || 0) +
          Number(stats.maintenance_checks || 0) +
          Number(stats.rental_checks || 0) +
          Number(stats.consumable_checks || 0),
        document_checks: Number(stats.document_checks || 0),
        maintenance_checks: Number(stats.maintenance_checks || 0),
        rental_checks: Number(stats.rental_checks || 0),
        consumable_checks: Number(stats.consumable_checks || 0),
      },
    });
  },
};
