import { pool } from "../db/pool.js";
import { ApiError } from "../utils/ApiError.js";
import { exportReportAsExcel, exportReportAsPdf } from "../utils/reportExport.js";
import { formatDzdAmount, toNumber } from "../utils/formatters.js";

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

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

  return companyId;
};

const cleanString = (value) => String(value ?? "").trim();
const nullableString = (value) => {
  const cleaned = cleanString(value);
  return cleaned || null;
};
const nullableNumber = (value) => {
  if (value === "" || value === null || value === undefined) return null;
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : null;
};

const todayIso = new Date().toISOString().slice(0, 10);
const yearStartIso = new Date(new Date().getFullYear(), 0, 1).toISOString().slice(0, 10);
const monthStartIso = new Date(new Date().getFullYear(), new Date().getMonth(), 1)
  .toISOString()
  .slice(0, 10);

const formatDateValue = (value) => {
  if (!value) return "—";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return String(value);
  return new Intl.DateTimeFormat("fr-FR").format(date);
};

const parseFileName = (base, extension) =>
  `${String(base || "rapport")
    .toLowerCase()
    .replace(/[^a-z0-9-_]+/gi, "-")}.${extension}`;

const fetchCompany = async (db, companyId) => {
  const { rows } = await db.query(
    `
      SELECT id, name, nif, rc, address, city, logo_url
      FROM companies
      WHERE id = $1
      LIMIT 1
    `,
    [companyId],
  );

  return rows[0] || { id: companyId, name: "Société" };
};

const sendExport = async (res, report, exportType) => {
  if (exportType === "pdf") {
    const buffer = await exportReportAsPdf(report);
    res.setHeader("Content-Type", "application/pdf");
    res.setHeader("Content-Disposition", `attachment; filename="${parseFileName(report.export_filename || report.report_key, "pdf")}"`);
    res.send(Buffer.from(buffer));
    return;
  }

  if (exportType === "excel" || exportType === "xlsx") {
    const buffer = await exportReportAsExcel(report);
    res.setHeader("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    res.setHeader("Content-Disposition", `attachment; filename="${parseFileName(report.export_filename || report.report_key, "xlsx")}"`);
    res.send(Buffer.from(buffer));
    return;
  }

  throw new ApiError(400, "Format d'export non supporté.");
};

const buildBaseReport = ({ reportKey, title, company, parameters = [], cards = [], table = null, sections = [], summary = [], exportFilename = null, landscape = true }) => ({
  report_key: reportKey,
  title,
  company,
  parameters,
  cards,
  table,
  sections,
  summary,
  export_filename: exportFilename || reportKey,
  generated_at: new Date().toISOString(),
  generated_by: "Compta Control",
  landscape,
});

const maybeExport = async (req, res, report) => {
  const exportType = cleanString(req.query.export).toLowerCase();

  if (!exportType) {
    return false;
  }

  await sendExport(res, report, exportType);
  return true;
};

const amountColumn = (key, label) => ({ key, label, type: "amount" });
const dateColumn = (key, label) => ({ key, label, type: "date" });

const buildVehiclesDataset = async (db, companyId, query) => {
  const params = [companyId];
  const filters = ["v.company_id = $1"];

  if (nullableNumber(query.depot_id)) {
    params.push(Number(query.depot_id));
    filters.push(`v.depot_id = $${params.length}`);
  }
  if (nullableNumber(query.category)) {
    params.push(Number(query.category));
    filters.push(`v.category_ref_id = $${params.length}`);
  }
  if (nullableNumber(query.status)) {
    params.push(Number(query.status));
    filters.push(`v.status_ref_id = $${params.length}`);
  }
  if (query.active_only === "true") {
    filters.push("v.is_active = TRUE");
  }

  const { rows } = await db.query(
    `
      SELECT
        v.id,
        v.reference,
        v.plate_number,
        v.brand,
        v.model,
        category.label AS category_label,
        status.label AS status_label,
        depot.label AS depot_label,
        v.year,
        v.km_current,
        v.assigned_driver,
        v.acquisition_date,
        v.acquisition_value,
        v.is_active
      FROM mgx_vehicles v
      LEFT JOIN mgx_referentiels category ON category.id = v.category_ref_id
      LEFT JOIN mgx_referentiels status ON status.id = v.status_ref_id
      LEFT JOIN mgx_depots depot ON depot.id = v.depot_id
      WHERE ${filters.join(" AND ")}
      ORDER BY v.reference ASC, v.plate_number ASC
    `,
    params,
  );

  return rows.map((row) => ({
    id: Number(row.id),
    reference: row.reference,
    plate_number: row.plate_number,
    vehicle: `${row.brand || ""} ${row.model || ""}`.trim() || "—",
    category_label: row.category_label || "—",
    status_label: row.status_label || "—",
    depot_label: row.depot_label || "—",
    year: row.year || "—",
    km_current: toNumber(row.km_current),
    km_current_display: `${Math.round(toNumber(row.km_current)).toLocaleString("fr-FR")} km`,
    assigned_driver: row.assigned_driver || "—",
    acquisition_date: row.acquisition_date,
    acquisition_value: toNumber(row.acquisition_value),
    is_active: Boolean(row.is_active),
  }));
};

const buildFuelHistoryDataset = async (db, companyId, query) => {
  const params = [companyId];
  const filters = ["f.company_id = $1"];

  if (nullableNumber(query.vehicle_id)) {
    params.push(Number(query.vehicle_id));
    filters.push(`f.vehicle_id = $${params.length}`);
  }
  if (nullableNumber(query.depot_id)) {
    params.push(Number(query.depot_id));
    filters.push(`f.depot_id = $${params.length}`);
  }
  if (nullableNumber(query.fuel_type_ref_id || query.fuel_type)) {
    params.push(Number(query.fuel_type_ref_id || query.fuel_type));
    filters.push(`f.fuel_type_ref_id = $${params.length}`);
  }
  if (query.from) {
    params.push(query.from);
    filters.push(`f.entry_date >= $${params.length}`);
  }
  if (query.to) {
    params.push(query.to);
    filters.push(`f.entry_date <= $${params.length}`);
  }

  const { rows } = await db.query(
    `
      SELECT
        f.id,
        f.entry_date,
        v.plate_number,
        v.brand,
        v.model,
        depot.label AS depot_label,
        fuel.label AS fuel_type_label,
        f.quantity,
        f.unit_price,
        f.total_amount,
        f.km_at_fillup,
        f.consumption_per_100,
        f.station_supplier,
        f.is_anomaly,
        f.anomaly_reason
      FROM mgx_fuel_entries f
      LEFT JOIN mgx_vehicles v ON v.id = f.vehicle_id
      LEFT JOIN mgx_depots depot ON depot.id = f.depot_id
      LEFT JOIN mgx_referentiels fuel ON fuel.id = f.fuel_type_ref_id
      WHERE ${filters.join(" AND ")}
      ORDER BY f.entry_date DESC, f.id DESC
    `,
    params,
  );

  return rows.map((row) => ({
    id: Number(row.id),
    entry_date: row.entry_date,
    vehicle: row.plate_number ? `${row.plate_number} · ${row.brand || ""} ${row.model || ""}`.trim() : "—",
    plate_number: row.plate_number || "—",
    depot_label: row.depot_label || "—",
    fuel_type_label: row.fuel_type_label || "—",
    quantity: toNumber(row.quantity),
    quantity_display: `${toNumber(row.quantity).toLocaleString("fr-FR", { minimumFractionDigits: 3, maximumFractionDigits: 3 })}`,
    unit_price: toNumber(row.unit_price),
    total_amount: toNumber(row.total_amount),
    km_at_fillup: toNumber(row.km_at_fillup),
    consumption_per_100: row.consumption_per_100 === null ? null : toNumber(row.consumption_per_100),
    station_supplier: row.station_supplier || "—",
    is_anomaly: Boolean(row.is_anomaly),
    anomaly_reason: row.anomaly_reason || "",
  }));
};

const buildMaintenanceHistoryDataset = async (db, companyId, query) => {
  const params = [companyId];
  const filters = ["i.company_id = $1"];

  if (nullableNumber(query.vehicle_id)) {
    params.push(Number(query.vehicle_id));
    filters.push(`i.vehicle_id = $${params.length}`);
  }
  if (nullableNumber(query.depot_id)) {
    params.push(Number(query.depot_id));
    filters.push(`i.depot_id = $${params.length}`);
  }
  if (nullableNumber(query.type || query.maintenance_type_ref_id)) {
    params.push(Number(query.type || query.maintenance_type_ref_id));
    filters.push(`i.maintenance_type_ref_id = $${params.length}`);
  }
  if (nullableNumber(query.status)) {
    params.push(Number(query.status));
    filters.push(`i.status_ref_id = $${params.length}`);
  }
  if (query.from) {
    params.push(query.from);
    filters.push(`i.start_date >= $${params.length}`);
  }
  if (query.to) {
    params.push(query.to);
    filters.push(`i.start_date <= $${params.length}`);
  }

  const { rows } = await db.query(
    `
      SELECT
        i.id,
        i.start_date,
        i.end_date,
        i.label,
        i.total_cost,
        i.next_date,
        i.next_km,
        v.plate_number,
        v.brand,
        v.model,
        depot.label AS depot_label,
        maintenance_type.label AS maintenance_type_label,
        status.label AS status_label,
        supplier.name AS supplier_name
      FROM mgx_interventions i
      LEFT JOIN mgx_vehicles v ON v.id = i.vehicle_id
      LEFT JOIN mgx_depots depot ON depot.id = i.depot_id
      LEFT JOIN mgx_referentiels maintenance_type ON maintenance_type.id = i.maintenance_type_ref_id
      LEFT JOIN mgx_referentiels status ON status.id = i.status_ref_id
      LEFT JOIN mgx_suppliers supplier ON supplier.id = i.supplier_id
      WHERE ${filters.join(" AND ")}
      ORDER BY i.start_date DESC, i.id DESC
    `,
    params,
  );

  return rows.map((row) => ({
    id: Number(row.id),
    start_date: row.start_date,
    vehicle: row.plate_number ? `${row.plate_number} · ${row.brand || ""} ${row.model || ""}`.trim() : "—",
    plate_number: row.plate_number || "—",
    depot_label: row.depot_label || "—",
    maintenance_type_label: row.maintenance_type_label || "—",
    label: row.label || "—",
    supplier_name: row.supplier_name || "—",
    total_cost: toNumber(row.total_cost),
    status_label: row.status_label || "—",
    next_maintenance: row.next_date
      ? `${formatDateValue(row.next_date)}${row.next_km ? ` · ${Math.round(toNumber(row.next_km)).toLocaleString("fr-FR")} km` : ""}`
      : row.next_km
        ? `${Math.round(toNumber(row.next_km)).toLocaleString("fr-FR")} km`
        : "—",
  }));
};

const buildDocumentsExpiryDataset = async (db, companyId, query) => {
  const days = Number(query.days || 30);
  const params = [companyId, days];
  const filters = ["doc.company_id = $1", "doc.status = 'active'", "doc.expiry_date <= CURRENT_DATE + ($2::int * INTERVAL '1 day')"];

  if (nullableNumber(query.depot_id)) {
    params.push(Number(query.depot_id));
    filters.push(`vehicle.depot_id = $${params.length}`);
  }
  if (nullableNumber(query.document_type_id || query.type)) {
    params.push(Number(query.document_type_id || query.type));
    filters.push(`doc.document_type_ref_id = $${params.length}`);
  }

  const { rows } = await db.query(
    `
      SELECT
        doc.id,
        vehicle.plate_number,
        depot.label AS depot_label,
        document_type.label AS document_type_label,
        doc.reference_number,
        doc.issuer,
        doc.expiry_date,
        doc.amount,
        (doc.expiry_date - CURRENT_DATE)::int AS days_remaining
      FROM mgx_vehicle_documents doc
      LEFT JOIN mgx_vehicles vehicle ON vehicle.id = doc.vehicle_id
      LEFT JOIN mgx_depots depot ON depot.id = vehicle.depot_id
      LEFT JOIN mgx_referentiels document_type ON document_type.id = doc.document_type_ref_id
      WHERE ${filters.join(" AND ")}
      ORDER BY doc.expiry_date ASC, doc.id DESC
    `,
    params,
  );

  return rows.map((row) => ({
    id: Number(row.id),
    plate_number: row.plate_number || "—",
    depot_label: row.depot_label || "—",
    document_type_label: row.document_type_label || "—",
    reference_number: row.reference_number || "—",
    issuer: row.issuer || "—",
    expiry_date: row.expiry_date,
    days_remaining: Number(row.days_remaining ?? 0),
    amount: toNumber(row.amount),
  }));
};

const buildPurchasesDataset = async (db, companyId, query) => {
  const params = [companyId];
  const filters = ["po.company_id = $1"];

  if (query.from) {
    params.push(query.from);
    filters.push(`po.order_date >= $${params.length}`);
  }
  if (query.to) {
    params.push(query.to);
    filters.push(`po.order_date <= $${params.length}`);
  }
  if (nullableNumber(query.depot_id)) {
    params.push(Number(query.depot_id));
    filters.push(`po.depot_id = $${params.length}`);
  }
  if (nullableNumber(query.category)) {
    params.push(Number(query.category));
    filters.push(`po.category_ref_id = $${params.length}`);
  }
  if (nullableNumber(query.supplier_id)) {
    params.push(Number(query.supplier_id));
    filters.push(`po.supplier_id = $${params.length}`);
  }
  if (nullableNumber(query.status)) {
    params.push(Number(query.status));
    filters.push(`po.status_ref_id = $${params.length}`);
  }

  const { rows } = await db.query(
    `
      SELECT
        po.id,
        po.order_number,
        po.order_date,
        po.total_ht,
        po.total_ttc,
        po.delivery_date_expected,
        supplier.name AS supplier_name,
        depot.label AS depot_label,
        category.label AS category_label,
        status.label AS status_label
      FROM mgx_purchase_orders po
      LEFT JOIN mgx_suppliers supplier ON supplier.id = po.supplier_id
      LEFT JOIN mgx_depots depot ON depot.id = po.depot_id
      LEFT JOIN mgx_referentiels category ON category.id = po.category_ref_id
      LEFT JOIN mgx_referentiels status ON status.id = po.status_ref_id
      WHERE ${filters.join(" AND ")}
      ORDER BY po.order_date DESC, po.id DESC
    `,
    params,
  );

  return rows.map((row) => ({
    id: Number(row.id),
    order_number: row.order_number,
    order_date: row.order_date,
    supplier_name: row.supplier_name || "—",
    depot_label: row.depot_label || "—",
    category_label: row.category_label || "—",
    total_ttc: toNumber(row.total_ttc || row.total_ht),
    status_label: row.status_label || "—",
    delivery_date_expected: row.delivery_date_expected,
  }));
};

const buildRentalsDataset = async (db, companyId, query) => {
  const params = [companyId];
  const filters = ["r.company_id = $1"];

  if (nullableNumber(query.depot_id)) {
    params.push(Number(query.depot_id));
    filters.push(`vehicle.depot_id = $${params.length}`);
  }
  if (nullableNumber(query.status)) {
    params.push(Number(query.status));
    filters.push(`r.status_ref_id = $${params.length}`);
  }

  const { rows } = await db.query(
    `
      SELECT
        r.id,
        vehicle.plate_number,
        supplier.name AS supplier_name,
        r.start_date,
        r.end_date,
        r.daily_rate,
        r.total_amount,
        status.label AS status_label,
        COALESCE((r.end_date - CURRENT_DATE)::int, 0) AS days_remaining
      FROM mgx_rentals r
      LEFT JOIN mgx_vehicles vehicle ON vehicle.id = r.vehicle_id
      LEFT JOIN mgx_suppliers supplier ON supplier.id = r.supplier_id
      LEFT JOIN mgx_referentiels status ON status.id = r.status_ref_id
      WHERE ${filters.join(" AND ")}
      ORDER BY r.start_date DESC, r.id DESC
    `,
    params,
  );

  return rows.map((row) => ({
    id: Number(row.id),
    plate_number: row.plate_number || "—",
    supplier_name: row.supplier_name || "—",
    start_date: row.start_date,
    end_date: row.end_date,
    daily_rate: toNumber(row.daily_rate),
    total_amount: toNumber(row.total_amount),
    status_label: row.status_label || "—",
    days_remaining: Number(row.days_remaining || 0),
  }));
};

const buildTreasuryJournalDataset = async (db, companyId, query) => {
  const params = [companyId];
  const filters = ["tm.company_id = $1"];

  if (query.from) {
    params.push(query.from);
    filters.push(`tm.movement_date >= $${params.length}`);
  }
  if (query.to) {
    params.push(query.to);
    filters.push(`tm.movement_date <= $${params.length}`);
  }
  if (nullableNumber(query.depot_id)) {
    params.push(Number(query.depot_id));
    filters.push(`tm.depot_id = $${params.length}`);
  }
  if (query.type) {
    params.push(query.type);
    filters.push(`tm.treasury_type = $${params.length}`);
  }
  if (nullableNumber(query.expense_type_ref_id || query.expense_type)) {
    params.push(Number(query.expense_type_ref_id || query.expense_type));
    filters.push(`tm.expense_type_ref_id = $${params.length}`);
  }

  const { rows } = await db.query(
    `
      SELECT
        tm.id,
        tm.movement_date,
        tm.treasury_type,
        tm.account_name,
        tm.direction,
        tm.amount,
        tm.label,
        tm.reference_type,
        tm.receipt_number,
        depot.label AS depot_label,
        expense.label AS expense_type_label
      FROM mgx_treasury_movements tm
      LEFT JOIN mgx_depots depot ON depot.id = tm.depot_id
      LEFT JOIN mgx_referentiels expense ON expense.id = tm.expense_type_ref_id
      WHERE ${filters.join(" AND ")}
      ORDER BY tm.account_name ASC, tm.movement_date ASC, tm.id ASC
    `,
    params,
  );

  let balanceByAccount = new Map();

  return rows.map((row) => {
    const key = `${row.treasury_type || ""}:${row.account_name || ""}`;
    const next = (balanceByAccount.get(key) || 0) + (row.direction === "in" ? toNumber(row.amount) : -toNumber(row.amount));
    balanceByAccount.set(key, next);

    return {
      id: Number(row.id),
      movement_date: row.movement_date,
      treasury_type: row.treasury_type === "bank" ? "Banque" : "Caisse",
      account_name: row.account_name || "—",
      label: row.label || "—",
      expense_type_label: row.expense_type_label || "—",
      entry_amount: row.direction === "in" ? toNumber(row.amount) : 0,
      out_amount: row.direction === "out" ? toNumber(row.amount) : 0,
      running_balance: next,
      depot_label: row.depot_label || "—",
      reference: [row.reference_type, row.receipt_number].filter(Boolean).join(" · ") || "—",
    };
  });
};

const buildCostByVehicleDataset = async (db, companyId, query) => {
  const from = query.from || yearStartIso;
  const to = query.to || todayIso;
  const params = [companyId, from, to];
  const filters = ["v.company_id = $1"];

  if (nullableNumber(query.depot_id)) {
    params.push(Number(query.depot_id));
    filters.push(`v.depot_id = $${params.length}`);
  }
  if (nullableNumber(query.category || query.category_ref_id)) {
    params.push(Number(query.category || query.category_ref_id));
    filters.push(`v.category_ref_id = $${params.length}`);
  }

  const { rows } = await db.query(
    `
      WITH km_range AS (
        SELECT
          vehicle_id,
          MAX(km_value) - MIN(km_value) AS km_done
        FROM mgx_vehicle_km_history
        WHERE reading_date BETWEEN $2::date AND $3::date
        GROUP BY vehicle_id
      ),
      fuel AS (
        SELECT vehicle_id, COALESCE(SUM(total_amount), 0) AS fuel_amount
        FROM mgx_fuel_entries
        WHERE company_id = $1
          AND entry_date BETWEEN $2::date AND $3::date
        GROUP BY vehicle_id
      ),
      maintenance AS (
        SELECT vehicle_id, COALESCE(SUM(total_cost), 0) AS maintenance_amount
        FROM mgx_interventions
        WHERE company_id = $1
          AND start_date BETWEEN $2::date AND $3::date
        GROUP BY vehicle_id
      ),
      services AS (
        SELECT vehicle_id, COALESCE(SUM(amount), 0) AS services_amount
        FROM mgx_services
        WHERE company_id = $1
          AND service_date BETWEEN $2::date AND $3::date
        GROUP BY vehicle_id
      ),
      rentals AS (
        SELECT vehicle_id, COALESCE(SUM(total_amount), 0) AS rentals_amount
        FROM mgx_rentals
        WHERE company_id = $1
          AND start_date BETWEEN $2::date AND $3::date
        GROUP BY vehicle_id
      ),
      purchases AS (
        SELECT
          pol.vehicle_id,
          COALESCE(SUM(pol.total), 0) AS purchases_amount
        FROM mgx_purchase_order_lines pol
        JOIN mgx_purchase_orders po ON po.id = pol.order_id
        WHERE po.company_id = $1
          AND po.order_date BETWEEN $2::date AND $3::date
          AND pol.vehicle_id IS NOT NULL
        GROUP BY pol.vehicle_id
      )
      SELECT
        v.id,
        v.plate_number,
        depot.label AS depot_label,
        category.label AS category_label,
        COALESCE(km_range.km_done, 0) AS km_done,
        COALESCE(fuel.fuel_amount, 0) AS fuel_amount,
        COALESCE(maintenance.maintenance_amount, 0) AS maintenance_amount,
        COALESCE(services.services_amount, 0) AS services_amount,
        COALESCE(rentals.rentals_amount, 0) AS rentals_amount,
        COALESCE(purchases.purchases_amount, 0) AS purchases_amount
      FROM mgx_vehicles v
      LEFT JOIN mgx_depots depot ON depot.id = v.depot_id
      LEFT JOIN mgx_referentiels category ON category.id = v.category_ref_id
      LEFT JOIN km_range ON km_range.vehicle_id = v.id
      LEFT JOIN fuel ON fuel.vehicle_id = v.id
      LEFT JOIN maintenance ON maintenance.vehicle_id = v.id
      LEFT JOIN services ON services.vehicle_id = v.id
      LEFT JOIN rentals ON rentals.vehicle_id = v.id
      LEFT JOIN purchases ON purchases.vehicle_id = v.id
      WHERE ${filters.join(" AND ")}
      ORDER BY (
        COALESCE(fuel.fuel_amount, 0) +
        COALESCE(maintenance.maintenance_amount, 0) +
        COALESCE(services.services_amount, 0) +
        COALESCE(rentals.rentals_amount, 0) +
        COALESCE(purchases.purchases_amount, 0)
      ) DESC, v.plate_number ASC
    `,
    params,
  );

  return rows.map((row) => {
    const total = toNumber(row.fuel_amount) +
      toNumber(row.maintenance_amount) +
      toNumber(row.services_amount) +
      toNumber(row.rentals_amount) +
      toNumber(row.purchases_amount);
    const kmDone = toNumber(row.km_done);

    return {
      id: Number(row.id),
      plate_number: row.plate_number || "—",
      depot_label: row.depot_label || "—",
      category_label: row.category_label || "—",
      km_done: kmDone,
      fuel_amount: toNumber(row.fuel_amount),
      maintenance_amount: toNumber(row.maintenance_amount),
      services_amount: toNumber(row.services_amount),
      rentals_amount: toNumber(row.rentals_amount),
      purchases_amount: toNumber(row.purchases_amount),
      total_amount: total,
      cost_per_km: kmDone > 0 ? total / kmDone : 0,
    };
  });
};

const buildCostByDepotDataset = async (db, companyId, query) => {
  const from = query.from || yearStartIso;
  const to = query.to || todayIso;
  const { rows } = await db.query(
    `
      WITH current_period AS (
        SELECT
          depot.id,
          depot.label AS depot_label,
          COUNT(DISTINCT vehicle.id)::int AS vehicles_count,
          COALESCE(SUM(DISTINCT fuel.total_amount), 0) AS fuel_amount,
          COALESCE(SUM(DISTINCT interventions.total_cost), 0) AS maintenance_amount,
          COALESCE(SUM(DISTINCT consumables.total_value), 0) AS consumables_amount,
          COALESCE(SUM(DISTINCT purchases.total_ttc), 0) AS purchases_amount
        FROM mgx_depots depot
        LEFT JOIN mgx_vehicles vehicle ON vehicle.depot_id = depot.id AND vehicle.company_id = $1
        LEFT JOIN mgx_fuel_entries fuel ON fuel.depot_id = depot.id AND fuel.company_id = $1 AND fuel.entry_date BETWEEN $2::date AND $3::date
        LEFT JOIN mgx_interventions interventions ON interventions.depot_id = depot.id AND interventions.company_id = $1 AND interventions.start_date BETWEEN $2::date AND $3::date
        LEFT JOIN mgx_consumable_movements consumables ON consumables.depot_id = depot.id AND consumables.company_id = $1 AND consumables.movement_type IN ('out','adjustment') AND consumables.movement_date BETWEEN $2::date AND $3::date
        LEFT JOIN mgx_purchase_orders purchases ON purchases.depot_id = depot.id AND purchases.company_id = $1 AND purchases.order_date BETWEEN $2::date AND $3::date
        WHERE depot.company_id = $1
        GROUP BY depot.id, depot.label
      ),
      previous_period AS (
        SELECT
          depot.id,
          COALESCE(SUM(fuel.total_amount), 0) +
          COALESCE(SUM(interventions.total_cost), 0) +
          COALESCE(SUM(consumables.total_value), 0) +
          COALESCE(SUM(purchases.total_ttc), 0) AS previous_total
        FROM mgx_depots depot
        LEFT JOIN mgx_fuel_entries fuel ON fuel.depot_id = depot.id AND fuel.company_id = $1 AND fuel.entry_date BETWEEN ($2::date - (($3::date - $2::date) + 1)) AND ($2::date - INTERVAL '1 day')
        LEFT JOIN mgx_interventions interventions ON interventions.depot_id = depot.id AND interventions.company_id = $1 AND interventions.start_date BETWEEN ($2::date - (($3::date - $2::date) + 1)) AND ($2::date - INTERVAL '1 day')
        LEFT JOIN mgx_consumable_movements consumables ON consumables.depot_id = depot.id AND consumables.company_id = $1 AND consumables.movement_type IN ('out','adjustment') AND consumables.movement_date BETWEEN ($2::date - (($3::date - $2::date) + 1)) AND ($2::date - INTERVAL '1 day')
        LEFT JOIN mgx_purchase_orders purchases ON purchases.depot_id = depot.id AND purchases.company_id = $1 AND purchases.order_date BETWEEN ($2::date - (($3::date - $2::date) + 1)) AND ($2::date - INTERVAL '1 day')
        WHERE depot.company_id = $1
        GROUP BY depot.id
      )
      SELECT
        current_period.*,
        COALESCE(previous_period.previous_total, 0) AS previous_total
      FROM current_period
      LEFT JOIN previous_period ON previous_period.id = current_period.id
      ORDER BY (
        current_period.fuel_amount +
        current_period.maintenance_amount +
        current_period.consumables_amount +
        current_period.purchases_amount
      ) DESC, current_period.depot_label ASC
    `,
    [companyId, from, to],
  );

  return rows.map((row) => {
    const total = toNumber(row.fuel_amount) + toNumber(row.maintenance_amount) + toNumber(row.consumables_amount) + toNumber(row.purchases_amount);
    const previousTotal = toNumber(row.previous_total);

    return {
      id: Number(row.id),
      depot_label: row.depot_label,
      vehicles_count: Number(row.vehicles_count || 0),
      fuel_amount: toNumber(row.fuel_amount),
      maintenance_amount: toNumber(row.maintenance_amount),
      consumables_amount: toNumber(row.consumables_amount),
      purchases_amount: toNumber(row.purchases_amount),
      total_amount: total,
      previous_total: previousTotal,
      evolution_value: total - previousTotal,
      evolution_pct: previousTotal > 0 ? ((total - previousTotal) / previousTotal) * 100 : null,
    };
  });
};

const buildConsumablesByDepotDataset = async (db, companyId, query) => {
  const from = query.from || monthStartIso;
  const to = query.to || todayIso;
  const params = [companyId, from, to];
  const filters = ["i.company_id = $1"];

  if (nullableNumber(query.depot_id)) {
    params.push(Number(query.depot_id));
    filters.push(`m.depot_id = $${params.length}`);
  }
  if (nullableNumber(query.category || query.category_ref_id)) {
    params.push(Number(query.category || query.category_ref_id));
    filters.push(`i.category_ref_id = $${params.length}`);
  }

  const { rows } = await db.query(
    `
      SELECT
        depot.id AS depot_id,
        depot.label AS depot_label,
        category.label AS category_label,
        i.id AS item_id,
        i.label AS item_label,
        COALESCE(SUM(CASE WHEN m.movement_type = 'in' THEN m.quantity ELSE 0 END), 0) AS qty_in,
        COALESCE(SUM(CASE WHEN m.movement_type IN ('out', 'adjustment') THEN m.quantity ELSE 0 END), 0) AS qty_out,
        MAX(i.current_stock_qty) AS stock_qty,
        COALESCE(SUM(CASE WHEN m.movement_type IN ('out', 'adjustment') THEN m.total_value ELSE 0 END), 0) AS consumed_value
      FROM mgx_consumable_movements m
      JOIN mgx_consumable_items i ON i.id = m.item_id
      LEFT JOIN mgx_depots depot ON depot.id = m.depot_id
      LEFT JOIN mgx_referentiels category ON category.id = i.category_ref_id
      WHERE ${filters.join(" AND ")}
        AND m.movement_date BETWEEN $2::date AND $3::date
      GROUP BY depot.id, depot.label, category.label, i.id, i.label
      ORDER BY depot.label ASC, category.label ASC, i.label ASC
    `,
    params,
  );

  return rows.map((row) => ({
    depot_id: Number(row.depot_id),
    depot_label: row.depot_label || "—",
    category_label: row.category_label || "—",
    item_id: Number(row.item_id),
    item_label: row.item_label || "—",
    qty_in: toNumber(row.qty_in),
    qty_out: toNumber(row.qty_out),
    stock_qty: toNumber(row.stock_qty),
    consumed_value: toNumber(row.consumed_value),
  }));
};

const buildExpenseByCategoryDataset = async (db, companyId, query) => {
  const from = query.from || monthStartIso;
  const to = query.to || todayIso;
  const params = [companyId, from, to];
  const filters = ["tm.company_id = $1"];

  if (nullableNumber(query.depot_id)) {
    params.push(Number(query.depot_id));
    filters.push(`tm.depot_id = $${params.length}`);
  }

  const { rows } = await db.query(
    `
      WITH current_period AS (
        SELECT
          expense.id,
          expense.label,
          expense.color,
          COALESCE(SUM(tm.amount), 0) AS amount
        FROM mgx_treasury_movements tm
        LEFT JOIN mgx_referentiels expense ON expense.id = tm.expense_type_ref_id
        WHERE ${filters.join(" AND ")}
          AND tm.direction = 'out'
          AND tm.movement_date BETWEEN $2::date AND $3::date
        GROUP BY expense.id, expense.label, expense.color
      ),
      prev_month AS (
        SELECT
          expense.id,
          COALESCE(SUM(tm.amount), 0) AS amount
        FROM mgx_treasury_movements tm
        LEFT JOIN mgx_referentiels expense ON expense.id = tm.expense_type_ref_id
        WHERE ${filters.join(" AND ")}
          AND tm.direction = 'out'
          AND tm.movement_date BETWEEN ($2::date - INTERVAL '1 month') AND ($3::date - INTERVAL '1 month')
        GROUP BY expense.id
      ),
      prev_year AS (
        SELECT
          expense.id,
          COALESCE(SUM(tm.amount), 0) AS amount
        FROM mgx_treasury_movements tm
        LEFT JOIN mgx_referentiels expense ON expense.id = tm.expense_type_ref_id
        WHERE ${filters.join(" AND ")}
          AND tm.direction = 'out'
          AND tm.movement_date BETWEEN ($2::date - INTERVAL '1 year') AND ($3::date - INTERVAL '1 year')
        GROUP BY expense.id
      )
      SELECT
        current_period.id,
        current_period.label,
        current_period.color,
        current_period.amount,
        COALESCE(prev_month.amount, 0) AS prev_month_amount,
        COALESCE(prev_year.amount, 0) AS prev_year_amount
      FROM current_period
      LEFT JOIN prev_month ON prev_month.id = current_period.id
      LEFT JOIN prev_year ON prev_year.id = current_period.id
      ORDER BY current_period.amount DESC, current_period.label ASC
    `,
    params,
  );

  const total = rows.reduce((sum, row) => sum + toNumber(row.amount), 0);

  return rows.map((row) => ({
    id: row.id ? Number(row.id) : 0,
    label: row.label || "Non défini",
    color: row.color || "#94A3B8",
    amount: toNumber(row.amount),
    percentage: total > 0 ? (toNumber(row.amount) / total) * 100 : 0,
    evolution_m1: toNumber(row.amount) - toNumber(row.prev_month_amount),
    evolution_a1: toNumber(row.amount) - toNumber(row.prev_year_amount),
  }));
};

const buildAlertsAnalysisDataset = async (db, companyId, query) => {
  const from = query.from || monthStartIso;
  const to = query.to || todayIso;
  const params = [companyId, from, to];
  const filters = ["a.company_id = $1", "a.created_at::date BETWEEN $2::date AND $3::date"];

  if (nullableNumber(query.type || query.alert_type_ref_id)) {
    params.push(Number(query.type || query.alert_type_ref_id));
    filters.push(`ac.alert_type_ref_id = $${params.length}`);
  }
  if (query.criticality) {
    params.push(query.criticality);
    filters.push(`a.criticality = $${params.length}`);
  }

  const [summaryResult, evolutionResult] = await Promise.all([
    db.query(
      `
        SELECT
          COALESCE(rt.id, 0) AS alert_type_id,
          COALESCE(rt.label, 'Non défini') AS label,
          COUNT(*)::int AS total_created,
          COUNT(*) FILTER (WHERE a.status = 'treated' AND (a.days_remaining IS NULL OR a.days_remaining >= 0))::int AS treated_on_time,
          COUNT(*) FILTER (WHERE a.status = 'treated' AND a.days_remaining < 0)::int AS treated_late
        FROM mgx_alerts a
        LEFT JOIN mgx_alert_configs ac ON ac.id = a.alert_config_id
        LEFT JOIN mgx_referentiels rt ON rt.id = ac.alert_type_ref_id
        WHERE ${filters.join(" AND ")}
        GROUP BY rt.id, rt.label
        ORDER BY total_created DESC, label ASC
      `,
      params,
    ),
    db.query(
      `
        SELECT
          TO_CHAR(date_trunc('week', a.created_at), 'DD/MM') AS period_label,
          COUNT(*)::int AS total_created
        FROM mgx_alerts a
        LEFT JOIN mgx_alert_configs ac ON ac.id = a.alert_config_id
        WHERE ${filters.join(" AND ")}
        GROUP BY date_trunc('week', a.created_at)
        ORDER BY MIN(date_trunc('week', a.created_at)) ASC
      `,
      params,
    ),
  ]);

  return {
    table: summaryResult.rows.map((row) => ({
      alert_type_id: Number(row.alert_type_id),
      label: row.label,
      total_created: Number(row.total_created || 0),
      treated_on_time: Number(row.treated_on_time || 0),
      treated_late: Number(row.treated_late || 0),
      treatment_rate: Number(row.total_created || 0) > 0
        ? ((Number(row.treated_on_time || 0) + Number(row.treated_late || 0)) / Number(row.total_created || 0)) * 100
        : 0,
    })),
    chart: evolutionResult.rows.map((row) => ({
      period_label: row.period_label,
      total_created: Number(row.total_created || 0),
    })),
  };
};

const buildDirectionSummaryDataset = async (db, companyId, query) => {
  const from = query.from || monthStartIso;
  const to = query.to || todayIso;
  const [kpis, expenseByCategory, costByDepot, costByVehicle, alertsByType] = await Promise.all([
    db.query(
      `
        SELECT
          (SELECT COUNT(*)::int FROM mgx_vehicles WHERE company_id = $1) AS park_total,
          (
            SELECT COUNT(*)::int
            FROM mgx_vehicles v
            LEFT JOIN mgx_referentiels s ON s.id = v.status_ref_id
            WHERE v.company_id = $1
              AND (LOWER(COALESCE(s.code, '')) IN ('active', 'actif') OR LOWER(COALESCE(s.label, '')) LIKE 'actif%')
          ) AS active_total,
          (
            SELECT COALESCE(SUM(amount), 0)
            FROM mgx_treasury_movements
            WHERE company_id = $1
              AND direction = 'out'
              AND movement_date BETWEEN $2::date AND $3::date
          ) AS total_cost,
          (
            SELECT COUNT(*)::int
            FROM mgx_alerts
            WHERE company_id = $1
              AND status = 'active'
              AND criticality = 'critical'
          ) AS critical_alerts,
          (
            SELECT COUNT(*)::int
            FROM mgx_suppliers
            WHERE company_id = $1
              AND is_active = TRUE
          ) AS active_suppliers
      `,
      [companyId, from, to],
    ),
    buildExpenseByCategoryDataset(db, companyId, { from, to }),
    buildCostByDepotDataset(db, companyId, { from, to }),
    buildCostByVehicleDataset(db, companyId, { from, to }),
    db.query(
      `
        SELECT
          COALESCE(rt.label, 'Non défini') AS label,
          a.criticality,
          COUNT(*)::int AS count
        FROM mgx_alerts a
        LEFT JOIN mgx_alert_configs ac ON ac.id = a.alert_config_id
        LEFT JOIN mgx_referentiels rt ON rt.id = ac.alert_type_ref_id
        WHERE a.company_id = $1
          AND a.status = 'active'
        GROUP BY rt.label, a.criticality
        ORDER BY count DESC, label ASC
      `,
      [companyId],
    ),
  ]);

  return {
    summary: {
      park_total: Number(kpis.rows[0]?.park_total || 0),
      active_total: Number(kpis.rows[0]?.active_total || 0),
      total_cost: toNumber(kpis.rows[0]?.total_cost),
      critical_alerts: Number(kpis.rows[0]?.critical_alerts || 0),
      active_suppliers: Number(kpis.rows[0]?.active_suppliers || 0),
    },
    expense_by_category: expenseByCategory,
    top_depots: costByDepot.slice(0, 5),
    top_vehicles: costByVehicle.slice(0, 5),
    alerts_by_type: alertsByType.rows.map((row) => ({
      label: row.label,
      criticality: row.criticality || "info",
      count: Number(row.count || 0),
    })),
  };
};

const buildSupplierBalanceDataset = async (db, companyId, query) => {
  const asOf = query.to || query.as_of || todayIso;
  const from = query.from || yearStartIso;
  const params = [companyId, from, asOf];
  const filters = ["s.company_id = $1", "s.is_active = TRUE"];

  if (nullableNumber(query.type || query.supplier_type_ref_id)) {
    params.push(Number(query.type || query.supplier_type_ref_id));
    filters.push(`s.supplier_type_ref_id = $${params.length}`);
  }

  const { rows } = await db.query(
    `
      WITH purchases AS (
        SELECT supplier_id, COALESCE(SUM(total_ttc), 0) AS amount
        FROM mgx_purchase_orders
        WHERE company_id = $1
          AND order_date BETWEEN $2::date AND $3::date
        GROUP BY supplier_id
      ),
      services AS (
        SELECT supplier_id, COALESCE(SUM(amount), 0) AS amount
        FROM mgx_services
        WHERE company_id = $1
          AND service_date BETWEEN $2::date AND $3::date
        GROUP BY supplier_id
      ),
      rentals AS (
        SELECT supplier_id, COALESCE(SUM(total_amount), 0) AS amount
        FROM mgx_rentals
        WHERE company_id = $1
          AND start_date BETWEEN $2::date AND $3::date
        GROUP BY supplier_id
      ),
      payments AS (
        SELECT supplier_id, COALESCE(SUM(amount), 0) AS amount
        FROM mgx_treasury_movements
        WHERE company_id = $1
          AND supplier_id IS NOT NULL
          AND direction = 'out'
          AND movement_date BETWEEN $2::date AND $3::date
        GROUP BY supplier_id
      )
      SELECT
        s.id,
        s.code,
        s.name,
        type.label AS supplier_type_label,
        COALESCE(purchases.amount, 0) + COALESCE(services.amount, 0) + COALESCE(rentals.amount, 0) AS total_purchases,
        COALESCE(payments.amount, 0) AS total_payments,
        (
          COALESCE(purchases.amount, 0) + COALESCE(services.amount, 0) + COALESCE(rentals.amount, 0) - COALESCE(payments.amount, 0)
        ) AS balance_due
      FROM mgx_suppliers s
      LEFT JOIN mgx_referentiels type ON type.id = s.supplier_type_ref_id
      LEFT JOIN purchases ON purchases.supplier_id = s.id
      LEFT JOIN services ON services.supplier_id = s.id
      LEFT JOIN rentals ON rentals.supplier_id = s.id
      LEFT JOIN payments ON payments.supplier_id = s.id
      WHERE ${filters.join(" AND ")}
      ORDER BY balance_due DESC, s.name ASC
    `,
    params,
  );

  return rows.map((row) => ({
    id: Number(row.id),
    code: row.code || "—",
    name: row.name || "—",
    supplier_type_label: row.supplier_type_label || "—",
    total_purchases: toNumber(row.total_purchases),
    total_payments: toNumber(row.total_payments),
    balance_due: toNumber(row.balance_due),
  }));
};

export const mgxReportsController = {
  async getVehiclesReport(req, res) {
    const companyId = getCompanyId(req);
    const company = await fetchCompany(pool, companyId);
    const items = await buildVehiclesDataset(pool, companyId, req.query);
    const report = buildBaseReport({
      reportKey: "mgx-vehicles",
      title: "Liste des véhicules MGX",
      company,
      parameters: [
        { label: "Dépôt", value: req.query.depot_id || "Tous" },
        { label: "Catégorie", value: req.query.category || "Toutes" },
        { label: "Statut", value: req.query.status || "Tous" },
      ],
      table: {
        columns: [
          { key: "reference", label: "Réf" },
          { key: "plate_number", label: "Immatriculation" },
          { key: "vehicle", label: "Marque / Modèle" },
          { key: "category_label", label: "Catégorie" },
          { key: "status_label", label: "Statut" },
          { key: "depot_label", label: "Dépôt" },
          { key: "year", label: "Année" },
          { key: "km_current_display", label: "Km actuel" },
          dateColumn("acquisition_date", "Acquisition"),
          amountColumn("acquisition_value", "Valeur"),
        ],
        rows: items,
        emptyMessage: "Aucun véhicule trouvé.",
      },
    });

    if (await maybeExport(req, res, report)) return;
    res.json({ company, items, report });
  },

  async getFuelHistoryReport(req, res) {
    const companyId = getCompanyId(req);
    const company = await fetchCompany(pool, companyId);
    const items = await buildFuelHistoryDataset(pool, companyId, req.query);
    const report = buildBaseReport({
      reportKey: "mgx-fuel-history",
      title: "Historique carburant",
      company,
      parameters: [
        { label: "Du", value: req.query.from || "—" },
        { label: "Au", value: req.query.to || "—" },
      ],
      table: {
        columns: [
          dateColumn("entry_date", "Date"),
          { key: "plate_number", label: "Véhicule" },
          { key: "fuel_type_label", label: "Type carburant" },
          { key: "quantity_display", label: "Qté" },
          amountColumn("total_amount", "Montant"),
          { key: "km_at_fillup", label: "Km" },
          { key: "consumption_per_100", label: "L/100km" },
          { key: "station_supplier", label: "Station" },
          { key: "anomaly_reason", label: "Anomalie" },
        ],
        rows: items,
        emptyMessage: "Aucune saisie carburant.",
      },
    });

    if (await maybeExport(req, res, report)) return;
    res.json({ company, items, report });
  },

  async getMaintenanceHistoryReport(req, res) {
    const companyId = getCompanyId(req);
    const company = await fetchCompany(pool, companyId);
    const items = await buildMaintenanceHistoryDataset(pool, companyId, req.query);
    const report = buildBaseReport({
      reportKey: "mgx-maintenance-history",
      title: "Historique entretiens",
      company,
      table: {
        columns: [
          dateColumn("start_date", "Date"),
          { key: "plate_number", label: "Véhicule" },
          { key: "maintenance_type_label", label: "Type" },
          { key: "label", label: "Libellé" },
          { key: "supplier_name", label: "Prestataire" },
          amountColumn("total_cost", "Coût"),
          { key: "status_label", label: "Statut" },
          { key: "next_maintenance", label: "Prochain entretien" },
        ],
        rows: items,
        emptyMessage: "Aucun entretien trouvé.",
      },
    });

    if (await maybeExport(req, res, report)) return;
    res.json({ company, items, report });
  },

  async getDocumentsExpiryReport(req, res) {
    const companyId = getCompanyId(req);
    const company = await fetchCompany(pool, companyId);
    const items = await buildDocumentsExpiryDataset(pool, companyId, req.query);
    const report = buildBaseReport({
      reportKey: "mgx-documents-expiry",
      title: "Documents à échéance",
      company,
      table: {
        columns: [
          { key: "plate_number", label: "Véhicule" },
          { key: "document_type_label", label: "Type document" },
          { key: "reference_number", label: "Référence" },
          { key: "issuer", label: "Organisme" },
          dateColumn("expiry_date", "Échéance"),
          { key: "days_remaining", label: "Jours restants" },
          amountColumn("amount", "Montant"),
        ],
        rows: items,
        emptyMessage: "Aucun document à échéance.",
      },
    });

    if (await maybeExport(req, res, report)) return;
    res.json({ company, items, report });
  },

  async getPurchasesReport(req, res) {
    const companyId = getCompanyId(req);
    const company = await fetchCompany(pool, companyId);
    const items = await buildPurchasesDataset(pool, companyId, req.query);
    const report = buildBaseReport({
      reportKey: "mgx-purchases",
      title: "Achats par période",
      company,
      table: {
        columns: [
          dateColumn("order_date", "Date"),
          { key: "order_number", label: "N° BC" },
          { key: "supplier_name", label: "Fournisseur" },
          { key: "category_label", label: "Catégorie" },
          { key: "depot_label", label: "Dépôt" },
          amountColumn("total_ttc", "Montant"),
          { key: "status_label", label: "Statut" },
          dateColumn("delivery_date_expected", "Livraison prévue"),
        ],
        rows: items,
        emptyMessage: "Aucun achat trouvé.",
      },
    });

    if (await maybeExport(req, res, report)) return;
    res.json({ company, items, report });
  },

  async getCostByVehicleReport(req, res) {
    const companyId = getCompanyId(req);
    const company = await fetchCompany(pool, companyId);
    const items = await buildCostByVehicleDataset(pool, companyId, req.query);
    const report = buildBaseReport({
      reportKey: "mgx-cost-by-vehicle",
      title: "Coût total par véhicule",
      company,
      table: {
        columns: [
          { key: "plate_number", label: "Véhicule" },
          { key: "km_done", label: "Km parcourus" },
          amountColumn("fuel_amount", "Carburant"),
          amountColumn("maintenance_amount", "Maintenance"),
          amountColumn("services_amount", "Prestations"),
          amountColumn("rentals_amount", "Locations"),
          amountColumn("purchases_amount", "Achats"),
          amountColumn("total_amount", "TOTAL"),
          amountColumn("cost_per_km", "Coût/km"),
        ],
        rows: items,
        emptyMessage: "Aucun coût véhicule.",
      },
    });

    if (await maybeExport(req, res, report)) return;
    res.json({ company, items, report });
  },

  async getCostByDepotReport(req, res) {
    const companyId = getCompanyId(req);
    const company = await fetchCompany(pool, companyId);
    const items = await buildCostByDepotDataset(pool, companyId, req.query);
    const report = buildBaseReport({
      reportKey: "mgx-cost-by-depot",
      title: "Coût total par dépôt",
      company,
      table: {
        columns: [
          { key: "depot_label", label: "Dépôt" },
          { key: "vehicles_count", label: "Nb véhicules" },
          amountColumn("fuel_amount", "Carburant"),
          amountColumn("maintenance_amount", "Maintenance"),
          amountColumn("consumables_amount", "Consommables"),
          amountColumn("purchases_amount", "Achats"),
          amountColumn("total_amount", "Total"),
          { key: "evolution_pct", label: "Évolution %" },
        ],
        rows: items,
        emptyMessage: "Aucun coût dépôt.",
      },
    });

    if (await maybeExport(req, res, report)) return;
    res.json({ company, items, report });
  },

  async getConsumablesByDepotReport(req, res) {
    const companyId = getCompanyId(req);
    const company = await fetchCompany(pool, companyId);
    const items = await buildConsumablesByDepotDataset(pool, companyId, req.query);
    const report = buildBaseReport({
      reportKey: "mgx-consumables-by-depot",
      title: "Consommation consommables par dépôt",
      company,
      table: {
        columns: [
          { key: "depot_label", label: "Dépôt" },
          { key: "category_label", label: "Catégorie" },
          { key: "item_label", label: "Article" },
          { key: "qty_in", label: "Qté entrée" },
          { key: "qty_out", label: "Qté sortie" },
          { key: "stock_qty", label: "Qté stock" },
          amountColumn("consumed_value", "Valeur consommée"),
        ],
        rows: items,
        emptyMessage: "Aucun mouvement consommable.",
      },
    });

    if (await maybeExport(req, res, report)) return;
    res.json({ company, items, report });
  },

  async getExpenseByCategoryReport(req, res) {
    const companyId = getCompanyId(req);
    const company = await fetchCompany(pool, companyId);
    const items = await buildExpenseByCategoryDataset(pool, companyId, req.query);
    const report = buildBaseReport({
      reportKey: "mgx-expense-by-category",
      title: "Analyse des dépenses par catégorie",
      company,
      table: {
        columns: [
          { key: "label", label: "Type de dépense" },
          amountColumn("amount", "Montant"),
          { key: "percentage", label: "% du total" },
          amountColumn("evolution_m1", "Évolution M-1"),
          amountColumn("evolution_a1", "Évolution A-1"),
        ],
        rows: items,
        emptyMessage: "Aucune dépense.",
      },
    });

    if (await maybeExport(req, res, report)) return;
    res.json({ company, items, report });
  },

  async getDirectionSummaryReport(req, res) {
    const companyId = getCompanyId(req);
    const company = await fetchCompany(pool, companyId);
    const data = await buildDirectionSummaryDataset(pool, companyId, req.query);
    const report = buildBaseReport({
      reportKey: "mgx-direction-summary",
      title: "Tableau de bord direction MGX",
      company,
      parameters: [
        { label: "Période du", value: req.query.from || monthStartIso },
        { label: "Période au", value: req.query.to || todayIso },
      ],
      cards: [
        { label: "Parc total", value: data.summary.park_total },
        { label: "Actifs", value: data.summary.active_total },
        { label: "Coût total période", value: data.summary.total_cost, type: "amount" },
        { label: "Alertes critiques", value: data.summary.critical_alerts },
        { label: "Fournisseurs actifs", value: data.summary.active_suppliers },
      ],
      sections: [
        {
          title: "Top 5 véhicules les plus coûteux",
          columns: [
            { key: "plate_number", label: "Véhicule" },
            amountColumn("total_amount", "Coût total"),
            amountColumn("cost_per_km", "Coût/km"),
          ],
          rows: data.top_vehicles,
        },
        {
          title: "Alertes en cours par criticité",
          columns: [
            { key: "label", label: "Type alerte" },
            { key: "criticality", label: "Criticité" },
            { key: "count", label: "Nombre" },
          ],
          rows: data.alerts_by_type,
        },
      ],
      landscape: false,
    });

    if (await maybeExport(req, res, report)) return;
    res.json({ company, ...data, report });
  },

  async getSupplierBalanceReport(req, res) {
    const companyId = getCompanyId(req);
    const company = await fetchCompany(pool, companyId);
    const items = await buildSupplierBalanceDataset(pool, companyId, req.query);
    const report = buildBaseReport({
      reportKey: "mgx-supplier-balance",
      title: "Balance fournisseurs MGX",
      company,
      table: {
        columns: [
          { key: "code", label: "Code" },
          { key: "name", label: "Nom" },
          { key: "supplier_type_label", label: "Type" },
          amountColumn("total_purchases", "Total achats période"),
          amountColumn("total_payments", "Total règlements"),
          amountColumn("balance_due", "Solde dû"),
        ],
        rows: items,
        emptyMessage: "Aucun fournisseur.",
      },
    });

    if (await maybeExport(req, res, report)) return;
    res.json({ company, items, report });
  },

  async getRentalsActive(req, res) {
    const companyId = getCompanyId(req);
    const company = await fetchCompany(pool, companyId);
    const items = await buildRentalsDataset(pool, companyId, req.query);
    const report = buildBaseReport({
      reportKey: "mgx-rentals-active",
      title: "Locations actives",
      company,
      table: {
        columns: [
          { key: "plate_number", label: "Véhicule" },
          { key: "supplier_name", label: "Loueur" },
          dateColumn("start_date", "Début"),
          dateColumn("end_date", "Fin"),
          amountColumn("daily_rate", "Tarif/j"),
          amountColumn("total_amount", "Total"),
          { key: "status_label", label: "Statut" },
          { key: "days_remaining", label: "Jours restants" },
        ],
        rows: items,
        emptyMessage: "Aucune location.",
      },
    });

    if (await maybeExport(req, res, report)) return;
    res.json({ company, items, report });
  },

  async getTreasuryJournal(req, res) {
    const companyId = getCompanyId(req);
    const company = await fetchCompany(pool, companyId);
    const items = await buildTreasuryJournalDataset(pool, companyId, req.query);
    const report = buildBaseReport({
      reportKey: "mgx-treasury-journal",
      title: "Journal de trésorerie MGX",
      company,
      table: {
        columns: [
          dateColumn("movement_date", "Date"),
          { key: "treasury_type", label: "Type" },
          { key: "account_name", label: "Compte" },
          { key: "label", label: "Libellé" },
          { key: "expense_type_label", label: "Type dépense" },
          amountColumn("entry_amount", "Entrée"),
          amountColumn("out_amount", "Sortie"),
          amountColumn("running_balance", "Solde"),
          { key: "depot_label", label: "Dépôt" },
          { key: "reference", label: "Référence" },
        ],
        rows: items,
        emptyMessage: "Aucun mouvement de trésorerie.",
      },
    });

    if (await maybeExport(req, res, report)) return;
    res.json({ company, items, report });
  },

  async getAlertsAnalysis(req, res) {
    const companyId = getCompanyId(req);
    const company = await fetchCompany(pool, companyId);
    const data = await buildAlertsAnalysisDataset(pool, companyId, req.query);
    const report = buildBaseReport({
      reportKey: "mgx-alerts-analysis",
      title: "Analyse des alertes MGX",
      company,
      table: {
        columns: [
          { key: "label", label: "Type alerte" },
          { key: "total_created", label: "Total créées" },
          { key: "treated_on_time", label: "Traitées à temps" },
          { key: "treated_late", label: "Traitées en retard" },
          { key: "treatment_rate", label: "Taux traitement %" },
        ],
        rows: data.table,
        emptyMessage: "Aucune alerte sur la période.",
      },
    });

    if (await maybeExport(req, res, report)) return;
    res.json({ company, ...data, report });
  },
};
