import { pool } from "../db/pool.js";
import { runMgxAlertEngine } from "../services/mgxAlertEngine.js";
import { ApiError } from "../utils/ApiError.js";
import { ensureMgxDriversTables } from "./mgxDriversController.js";

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 toNumber = (value, fallback = 0) => {
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : fallback;
};
const isoDateOnly = (value) => {
  const cleaned = nullableString(value);
  if (!cleaned) return null;
  return cleaned.slice(0, 10);
};
const todayIso = () => new Date().toISOString().slice(0, 10);

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 resolveActorUserId = (req) => (
  req.user?.accountType === "mgx_mobile_account" ? null : req.user?.sub || null
);

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,
      resolveActorUserId(req),
      action,
      entityType,
      entityId,
      oldData ? JSON.stringify(oldData) : null,
      newData ? JSON.stringify(newData) : null,
      req.ip,
    ],
  );
};

const ensureVehicleAssignmentTables = async (db = pool) => {
  await ensureMgxDriversTables(db);
  await db.query(`
    CREATE TABLE IF NOT EXISTS mgx_vehicle_driver_assignments (
      id BIGSERIAL PRIMARY KEY,
      company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
      vehicle_id BIGINT NOT NULL REFERENCES mgx_vehicles (id) ON DELETE CASCADE,
      driver_id BIGINT REFERENCES mgx_drivers (id) ON DELETE SET NULL,
      driver_name VARCHAR(200) NOT NULL,
      start_date DATE NOT NULL,
      end_date DATE,
      notes TEXT,
      created_by BIGINT REFERENCES users (id) ON DELETE SET NULL,
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
      updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
      CONSTRAINT chk_mgx_vehicle_driver_assignments_dates CHECK (end_date IS NULL OR end_date >= start_date)
    )
  `);
  await db.query(`
    ALTER TABLE mgx_vehicle_driver_assignments
      ADD COLUMN IF NOT EXISTS driver_id BIGINT
  `);
  await db.query(`
    DO $$
    BEGIN
      IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'fk_mgx_vehicle_driver_assignments_driver') THEN
        ALTER TABLE mgx_vehicle_driver_assignments
          ADD CONSTRAINT fk_mgx_vehicle_driver_assignments_driver
          FOREIGN KEY (driver_id) REFERENCES mgx_drivers (id) ON DELETE SET NULL;
      END IF;
    END $$;
  `);
  await db.query(`
    CREATE TABLE IF NOT EXISTS mgx_vehicle_depot_assignments (
      id BIGSERIAL PRIMARY KEY,
      company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
      vehicle_id BIGINT NOT NULL REFERENCES mgx_vehicles (id) ON DELETE CASCADE,
      depot_id BIGINT NOT NULL REFERENCES mgx_depots (id) ON DELETE RESTRICT,
      start_date DATE NOT NULL,
      end_date DATE,
      notes TEXT,
      created_by BIGINT REFERENCES users (id) ON DELETE SET NULL,
      created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
      updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
      CONSTRAINT chk_mgx_vehicle_depot_assignments_dates CHECK (end_date IS NULL OR end_date >= start_date)
    )
  `);
  await db.query(`
    CREATE INDEX IF NOT EXISTS idx_mgx_vehicle_driver_assignments_vehicle_dates
      ON mgx_vehicle_driver_assignments (vehicle_id, start_date DESC, id DESC)
  `);
  await db.query(`
    CREATE INDEX IF NOT EXISTS idx_mgx_vehicle_driver_assignments_driver_id
      ON mgx_vehicle_driver_assignments (driver_id)
  `);
  await db.query(`
    CREATE INDEX IF NOT EXISTS idx_mgx_vehicle_depot_assignments_vehicle_dates
      ON mgx_vehicle_depot_assignments (vehicle_id, start_date DESC, id DESC)
  `);
};

const triggerAlertEngine = (req, companyId) => {
  runMgxAlertEngine({
    companyId,
    io: req.app.get("io"),
  }).catch((error) => {
    console.error("MGX alert engine trigger failed after vehicle event", error);
  });
};

const mapRef = (prefix, row) => row[`${prefix}_id`] ? ({
  id: Number(row[`${prefix}_id`]),
  code: row[`${prefix}_code`],
  label: row[`${prefix}_label`],
  color: row[`${prefix}_color`],
  icon: row[`${prefix}_icon`],
  metadata: row[`${prefix}_metadata`] || {},
}) : null;

const formatDzdAmount = (value) =>
  new Intl.NumberFormat("fr-DZ", {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  }).format(toNumber(value)) + " DZD";

const mapVehicle = (row) => ({
  id: Number(row.id),
  company_id: Number(row.company_id),
  depot_id: row.depot_id ? Number(row.depot_id) : null,
  depot: row.depot_id ? {
    id: Number(row.depot_id),
    code: row.depot_code,
    label: row.depot_label,
    city: row.depot_city,
  } : null,
  driver_id: row.driver_id ? Number(row.driver_id) : null,
  driver: row.driver_id ? {
    id: Number(row.driver_id),
    code: row.driver_code,
    full_name: row.driver_full_name,
    phone: row.driver_phone,
    license_number: row.driver_license_number,
  } : null,
  reference: row.reference,
  code_camion: row.code_camion,
  plate_number: row.plate_number,
  brand: row.brand,
  model: row.model,
  category_ref_id: row.category_ref_id ? Number(row.category_ref_id) : null,
  category: mapRef("category", row),
  year: row.year ? Number(row.year) : null,
  chassis_number: row.chassis_number,
  fuel_type_ref_id: row.fuel_type_ref_id ? Number(row.fuel_type_ref_id) : null,
  fuel_type: mapRef("fuel", row),
  status_ref_id: row.status_ref_id ? Number(row.status_ref_id) : null,
  status: mapRef("status", row),
  km_initial: toNumber(row.km_initial),
  km_current: toNumber(row.km_current),
  hour_counter: row.hour_counter === null ? null : toNumber(row.hour_counter),
  acquisition_date: row.acquisition_date,
  acquisition_value: row.acquisition_value === null ? null : toNumber(row.acquisition_value),
  assigned_driver: row.assigned_driver,
  observations: row.observations,
  photo_url: row.photo_url,
  is_active: row.is_active,
  active_alerts_count: Number(row.active_alerts_count || 0),
  critical_alerts_count: Number(row.critical_alerts_count || 0),
  warning_alerts_count: Number(row.warning_alerts_count || 0),
  total_cost: toNumber(row.total_cost),
  total_cost_formatted: formatDzdAmount(row.total_cost),
  documents_count: Number(row.documents_count || 0),
  history_count: Number(row.history_count || 0),
  last_fuel_date: row.last_fuel_date,
  last_maintenance_date: row.last_maintenance_date,
  created_at: row.created_at,
  updated_at: row.updated_at,
});

const vehicleSelect = `
  SELECT
    v.*,
    d.code AS depot_code,
    d.label AS depot_label,
    d.city AS depot_city,
    driver.code AS driver_code,
    driver.full_name AS driver_full_name,
    driver.phone AS driver_phone,
    driver.license_number AS driver_license_number,
    cat.id AS category_id,
    cat.code AS category_code,
    cat.label AS category_label,
    cat.color AS category_color,
    cat.icon AS category_icon,
    cat.metadata AS category_metadata,
    fuel.id AS fuel_id,
    fuel.code AS fuel_code,
    fuel.label AS fuel_label,
    fuel.color AS fuel_color,
    fuel.icon AS fuel_icon,
    fuel.metadata AS fuel_metadata,
    status.id AS status_id,
    status.code AS status_code,
    status.label AS status_label,
    status.color AS status_color,
    status.icon AS status_icon,
    status.metadata AS status_metadata,
    COALESCE(alerts.active_alerts_count, 0) AS active_alerts_count,
    COALESCE(alerts.critical_alerts_count, 0) AS critical_alerts_count,
    COALESCE(alerts.warning_alerts_count, 0) AS warning_alerts_count,
    COALESCE(costs.total_cost, 0) AS total_cost,
    COALESCE(documents.documents_count, 0) AS documents_count,
    COALESCE(history.history_count, 0) AS history_count,
    last_fuel.last_fuel_date,
    last_maintenance.last_maintenance_date
  FROM mgx_vehicles v
  LEFT JOIN mgx_depots d ON d.id = v.depot_id
  LEFT JOIN mgx_drivers driver ON driver.id = v.driver_id
  LEFT JOIN mgx_referentiels cat ON cat.id = v.category_ref_id
  LEFT JOIN mgx_referentiels fuel ON fuel.id = v.fuel_type_ref_id
  LEFT JOIN mgx_referentiels status ON status.id = v.status_ref_id
  LEFT JOIN LATERAL (
    SELECT
      COUNT(*)::int AS active_alerts_count,
      COUNT(*) FILTER (WHERE criticality = 'critical')::int AS critical_alerts_count,
      COUNT(*) FILTER (WHERE criticality = 'warning')::int AS warning_alerts_count
    FROM mgx_alerts a
    WHERE a.vehicle_id = v.id
      AND a.status = 'active'
  ) alerts ON true
  LEFT JOIN LATERAL (
    SELECT
      COALESCE((SELECT SUM(total_amount) FROM mgx_fuel_entries f WHERE f.vehicle_id = v.id), 0) +
      COALESCE((SELECT SUM(total_cost) FROM mgx_interventions i WHERE i.vehicle_id = v.id), 0) +
      COALESCE((SELECT SUM(amount) FROM mgx_services s WHERE s.vehicle_id = v.id), 0) +
      COALESCE((SELECT SUM(total_amount) FROM mgx_rentals r WHERE r.vehicle_id = v.id), 0) AS total_cost
  ) costs ON true
  LEFT JOIN LATERAL (
    SELECT COUNT(*)::int AS documents_count
    FROM mgx_vehicle_documents doc
    WHERE doc.vehicle_id = v.id
  ) documents ON true
  LEFT JOIN LATERAL (
    SELECT
      (
        (SELECT COUNT(*) FROM mgx_fuel_entries f WHERE f.vehicle_id = v.id) +
        (SELECT COUNT(*) FROM mgx_interventions i WHERE i.vehicle_id = v.id) +
        (SELECT COUNT(*) FROM mgx_services s WHERE s.vehicle_id = v.id) +
        (SELECT COUNT(*) FROM mgx_rentals r WHERE r.vehicle_id = v.id) +
        (SELECT COUNT(*) FROM mgx_vehicle_km_history k WHERE k.vehicle_id = v.id) +
        (SELECT COUNT(*) FROM mgx_vehicle_driver_assignments da WHERE da.vehicle_id = v.id) +
        (SELECT COUNT(*) FROM mgx_vehicle_depot_assignments va WHERE va.vehicle_id = v.id)
      )::int AS history_count
  ) history ON true
  LEFT JOIN LATERAL (
    SELECT MAX(entry_date) AS last_fuel_date
    FROM mgx_fuel_entries f
    WHERE f.vehicle_id = v.id
  ) last_fuel ON true
  LEFT JOIN LATERAL (
    SELECT MAX(start_date) AS last_maintenance_date
    FROM mgx_interventions i
    WHERE i.vehicle_id = v.id
  ) last_maintenance ON true
`;

const buildVehiclePayload = (body) => ({
  company_id: Number(body.company_id),
  depot_id: nullableNumber(body.depot_id),
  reference: cleanString(body.reference).toUpperCase(),
  code_camion: nullableString(body.code_camion ? String(body.code_camion).toUpperCase() : ""),
  plate_number: cleanString(body.plate_number).toUpperCase(),
  brand: nullableString(body.brand),
  model: nullableString(body.model),
  category_ref_id: nullableNumber(body.category_ref_id),
  year: nullableNumber(body.year),
  chassis_number: nullableString(body.chassis_number),
  fuel_type_ref_id: nullableNumber(body.fuel_type_ref_id),
  status_ref_id: nullableNumber(body.status_ref_id),
  km_initial: toNumber(body.km_initial),
  km_current: toNumber(body.km_current),
  hour_counter: nullableNumber(body.hour_counter),
  acquisition_date: nullableString(body.acquisition_date),
  acquisition_value: nullableNumber(body.acquisition_value),
  driver_id: nullableNumber(body.driver_id),
  assigned_driver: nullableString(body.assigned_driver),
  driver_start_date: isoDateOnly(body.driver_start_date),
  driver_end_date: isoDateOnly(body.driver_end_date),
  depot_start_date: isoDateOnly(body.depot_start_date),
  depot_end_date: isoDateOnly(body.depot_end_date),
  assignment_notes: nullableString(body.assignment_notes),
  observations: nullableString(body.observations),
  photo_url: nullableString(body.photo_url),
  is_active: body.is_active !== false,
});

const closeActiveDriverAssignment = async (db, vehicleId, startDate) => {
  await db.query(
    `
      DELETE FROM mgx_vehicle_driver_assignments
      WHERE vehicle_id = $1
        AND end_date IS NULL
        AND start_date >= $2::date
    `,
    [vehicleId, startDate],
  );
  await db.query(
    `
      UPDATE mgx_vehicle_driver_assignments
      SET
        end_date = ($2::date - INTERVAL '1 day')::date,
        updated_at = NOW()
      WHERE vehicle_id = $1
        AND end_date IS NULL
        AND start_date < $2::date
    `,
    [vehicleId, startDate],
  );
};

const releaseDriverFromOtherVehicles = async (db, driverId, nextVehicleId, startDate) => {
  if (!driverId) return;

  const { rows } = await db.query(
    `
      SELECT id
      FROM mgx_vehicles
      WHERE driver_id = $1
        AND id <> $2
    `,
    [driverId, nextVehicleId],
  );

  if (!rows.length) return;

  await db.query(
    `
      UPDATE mgx_vehicles
      SET
        driver_id = NULL,
        assigned_driver = NULL,
        updated_at = NOW()
      WHERE driver_id = $1
        AND id <> $2
    `,
    [driverId, nextVehicleId],
  );

  for (const row of rows) {
    await closeActiveDriverAssignment(db, row.id, startDate);
  }
};

const closeActiveDepotAssignment = async (db, vehicleId, startDate) => {
  await db.query(
    `
      DELETE FROM mgx_vehicle_depot_assignments
      WHERE vehicle_id = $1
        AND end_date IS NULL
        AND start_date >= $2::date
    `,
    [vehicleId, startDate],
  );
  await db.query(
    `
      UPDATE mgx_vehicle_depot_assignments
      SET
        end_date = ($2::date - INTERVAL '1 day')::date,
        updated_at = NOW()
      WHERE vehicle_id = $1
        AND end_date IS NULL
        AND start_date < $2::date
    `,
    [vehicleId, startDate],
  );
};

const insertDriverAssignment = async (db, req, { companyId, vehicleId, driverId = null, driverName, startDate, endDate = null, notes = null }) => {
  if (!driverName) return null;
  if (endDate && endDate < startDate) {
    throw new ApiError(400, "La date fin chauffeur doit être supérieure ou égale à la date début.");
  }
  await releaseDriverFromOtherVehicles(db, driverId, vehicleId, startDate);
  await closeActiveDriverAssignment(db, vehicleId, startDate);
  const { rows } = await db.query(
    `
      INSERT INTO mgx_vehicle_driver_assignments (
        company_id, vehicle_id, driver_id, driver_name, start_date, end_date, notes, created_by
      )
      VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
      RETURNING *
    `,
    [companyId, vehicleId, driverId, driverName, startDate, endDate, notes, req.user?.sub || null],
  );
  return rows[0];
};

const resolveDriverSelection = async (db, companyId, driverId, fallbackName = null) => {
  if (!driverId) {
    return { driverId: null, driverName: nullableString(fallbackName) };
  }

  const { rows } = await db.query(
    `
      SELECT id, full_name
      FROM mgx_drivers
      WHERE id = $1
        AND company_id = $2
        AND is_active = TRUE
      LIMIT 1
    `,
    [driverId, companyId],
  );

  if (!rows[0]) {
    throw new ApiError(400, "Chauffeur sélectionné introuvable ou inactif.");
  }

  return {
    driverId: Number(rows[0].id),
    driverName: rows[0].full_name,
  };
};

const insertDepotAssignment = async (db, req, { companyId, vehicleId, depotId, startDate, endDate = null, notes = null }) => {
  if (!depotId) return null;
  if (endDate && endDate < startDate) {
    throw new ApiError(400, "La date fin dépôt doit être supérieure ou égale à la date début.");
  }
  await closeActiveDepotAssignment(db, vehicleId, startDate);
  const { rows } = await db.query(
    `
      INSERT INTO mgx_vehicle_depot_assignments (
        company_id, vehicle_id, depot_id, start_date, end_date, notes, created_by
      )
      VALUES ($1, $2, $3, $4, $5, $6, $7)
      RETURNING *
    `,
    [companyId, vehicleId, depotId, startDate, endDate, notes, req.user?.sub || null],
  );
  return rows[0];
};

const fetchVehicleById = async (db, id, companyId) => {
  await ensureVehicleAssignmentTables(db);
  const { rows } = await db.query(
    `
      ${vehicleSelect}
      WHERE v.id = $1
        AND v.company_id = $2
      LIMIT 1
    `,
    [id, companyId],
  );

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

const fetchCosts = async (db, vehicleId, periodFrom, periodTo) => {
  const { rows } = await db.query(
    `
      WITH bounds AS (
        SELECT
          COALESCE($2::date, date_trunc('year', CURRENT_DATE)::date) AS from_date,
          COALESCE($3::date, CURRENT_DATE) AS to_date,
          date_trunc('month', CURRENT_DATE)::date AS month_start,
          date_trunc('year', CURRENT_DATE)::date AS year_start
      ),
      categories AS (
        SELECT 'fuel' AS key, 'Carburant' AS label
        UNION ALL SELECT 'maintenance', 'Entretiens'
        UNION ALL SELECT 'services', 'Prestations'
        UNION ALL SELECT 'rentals', 'Locations'
      ),
      values AS (
        SELECT 'fuel' AS key, entry_date AS date, total_amount AS amount FROM mgx_fuel_entries WHERE vehicle_id = $1
        UNION ALL SELECT 'maintenance', start_date, total_cost FROM mgx_interventions WHERE vehicle_id = $1
        UNION ALL SELECT 'services', service_date, amount FROM mgx_services WHERE vehicle_id = $1
        UNION ALL SELECT 'rentals', start_date, total_amount FROM mgx_rentals WHERE vehicle_id = $1
      )
      SELECT
        c.key,
        c.label,
        COALESCE(SUM(v.amount) FILTER (WHERE v.date >= b.month_start AND v.date <= b.to_date), 0) AS current_month,
        COALESCE(SUM(v.amount) FILTER (WHERE v.date >= b.year_start AND v.date <= b.to_date), 0) AS current_year,
        COALESCE(SUM(v.amount), 0) AS total
      FROM categories c
      CROSS JOIN bounds b
      LEFT JOIN values v ON v.key = c.key
      GROUP BY c.key, c.label
      ORDER BY CASE c.key WHEN 'fuel' THEN 1 WHEN 'maintenance' THEN 2 WHEN 'services' THEN 3 ELSE 4 END
    `,
    [vehicleId, periodFrom || null, periodTo || null],
  );

  const items = rows.map((row) => ({
    key: row.key,
    label: row.label,
    current_month: toNumber(row.current_month),
    current_month_formatted: formatDzdAmount(row.current_month),
    current_year: toNumber(row.current_year),
    current_year_formatted: formatDzdAmount(row.current_year),
    total: toNumber(row.total),
    total_formatted: formatDzdAmount(row.total),
  }));

  const totals = items.reduce(
    (acc, item) => ({
      current_month: acc.current_month + item.current_month,
      current_year: acc.current_year + item.current_year,
      total: acc.total + item.total,
    }),
    { current_month: 0, current_year: 0, total: 0 },
  );

  const { rows: chartRows } = await db.query(
    `
      WITH months AS (
        SELECT generate_series(
          date_trunc('month', CURRENT_DATE)::date - INTERVAL '11 months',
          date_trunc('month', CURRENT_DATE)::date,
          INTERVAL '1 month'
        )::date AS month_start
      ),
      values AS (
        SELECT date_trunc('month', entry_date)::date AS month_start, 'fuel' AS key, total_amount AS amount FROM mgx_fuel_entries WHERE vehicle_id = $1
        UNION ALL SELECT date_trunc('month', start_date)::date, 'maintenance', total_cost FROM mgx_interventions WHERE vehicle_id = $1
        UNION ALL SELECT date_trunc('month', service_date)::date, 'services', amount FROM mgx_services WHERE vehicle_id = $1
        UNION ALL SELECT date_trunc('month', start_date)::date, 'rentals', total_amount FROM mgx_rentals WHERE vehicle_id = $1
      )
      SELECT
        m.month_start,
        COALESCE(SUM(v.amount) FILTER (WHERE v.key = 'fuel'), 0) AS fuel,
        COALESCE(SUM(v.amount) FILTER (WHERE v.key = 'maintenance'), 0) AS maintenance,
        COALESCE(SUM(v.amount) FILTER (WHERE v.key = 'services'), 0) AS services,
        COALESCE(SUM(v.amount) FILTER (WHERE v.key = 'rentals'), 0) AS rentals
      FROM months m
      LEFT JOIN values v ON v.month_start = m.month_start
      GROUP BY m.month_start
      ORDER BY m.month_start
    `,
    [vehicleId],
  );

  return {
    items,
    totals: {
      ...totals,
      current_month_formatted: formatDzdAmount(totals.current_month),
      current_year_formatted: formatDzdAmount(totals.current_year),
      total_formatted: formatDzdAmount(totals.total),
    },
    chart: chartRows.map((row) => ({
      month: row.month_start,
      label: new Intl.DateTimeFormat("fr-DZ", { month: "short" }).format(row.month_start),
      fuel: toNumber(row.fuel),
      maintenance: toNumber(row.maintenance),
      services: toNumber(row.services),
      rentals: toNumber(row.rentals),
    })),
  };
};

const mapDocument = (row) => {
  const expiryDate = row.expiry_date ? new Date(row.expiry_date) : null;
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  const daysUntilExpiry = expiryDate
    ? Math.ceil((expiryDate.getTime() - today.getTime()) / 86400000)
    : null;

  return {
    id: Number(row.id),
    vehicle_id: Number(row.vehicle_id),
    company_id: Number(row.company_id),
    document_type_ref_id: row.document_type_ref_id ? Number(row.document_type_ref_id) : null,
    type: mapRef("type", row),
    reference_number: row.reference_number,
    issuer: row.issuer,
    start_date: row.start_date,
    expiry_date: row.expiry_date,
    amount: row.amount === null ? null : toNumber(row.amount),
    amount_formatted: formatDzdAmount(row.amount),
    file_url: row.file_url,
    notes: row.notes,
    status: daysUntilExpiry !== null && daysUntilExpiry < 0 ? "expired" : row.status,
    alert_days_before: Number(row.alert_days_before || 30),
    days_until_expiry: daysUntilExpiry,
    created_at: row.created_at,
    updated_at: row.updated_at,
  };
};

const mapDriverAssignment = (row) => ({
  id: Number(row.id),
  company_id: Number(row.company_id),
  vehicle_id: Number(row.vehicle_id),
  driver_id: row.driver_id ? Number(row.driver_id) : null,
  driver_name: row.driver_name,
  start_date: row.start_date,
  end_date: row.end_date,
  notes: row.notes,
  created_at: row.created_at,
  updated_at: row.updated_at,
});

const mapDepotAssignment = (row) => ({
  id: Number(row.id),
  company_id: Number(row.company_id),
  vehicle_id: Number(row.vehicle_id),
  depot_id: Number(row.depot_id),
  depot: {
    id: Number(row.depot_id),
    code: row.depot_code,
    label: row.depot_label,
    city: row.depot_city,
  },
  start_date: row.start_date,
  end_date: row.end_date,
  notes: row.notes,
  created_at: row.created_at,
  updated_at: row.updated_at,
});

const documentSelect = `
  SELECT
    doc.*,
    type.id AS type_id,
    type.code AS type_code,
    type.label AS type_label,
    type.color AS type_color,
    type.icon AS type_icon,
    type.metadata AS type_metadata
  FROM mgx_vehicle_documents doc
  LEFT JOIN mgx_referentiels type ON type.id = doc.document_type_ref_id
`;

export const mgxVehiclesController = {
  async listVehicles(req, res) {
    const companyId = getCompanyId(req);
    await ensureVehicleAssignmentTables();
    const filters = {
      depotId: nullableNumber(req.query.depot_id),
      categoryId: nullableNumber(req.query.category),
      statusId: nullableNumber(req.query.status),
      fuelTypeId: nullableNumber(req.query.fuel_type),
      search: cleanString(req.query.search),
    };

    const conditions = ["v.company_id = $1", "v.is_active = true"];
    const values = [companyId];

    if (filters.depotId) {
      values.push(filters.depotId);
      conditions.push(`v.depot_id = $${values.length}`);
    }
    if (filters.categoryId) {
      values.push(filters.categoryId);
      conditions.push(`v.category_ref_id = $${values.length}`);
    }
    if (filters.statusId) {
      values.push(filters.statusId);
      conditions.push(`v.status_ref_id = $${values.length}`);
    }
    if (filters.fuelTypeId) {
      values.push(filters.fuelTypeId);
      conditions.push(`v.fuel_type_ref_id = $${values.length}`);
    }
    if (filters.search) {
      values.push(`%${filters.search.toLowerCase()}%`);
      conditions.push(`(
        lower(v.plate_number) LIKE $${values.length}
        OR lower(v.reference) LIKE $${values.length}
        OR lower(COALESCE(v.code_camion, '')) LIKE $${values.length}
        OR lower(COALESCE(v.brand, '')) LIKE $${values.length}
        OR lower(COALESCE(v.model, '')) LIKE $${values.length}
      )`);
    }

    const { rows } = await pool.query(
      `
        ${vehicleSelect}
        WHERE ${conditions.join(" AND ")}
        ORDER BY v.reference ASC, v.plate_number ASC
      `,
      values,
    );

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

  async getVehicle(req, res) {
    const companyId = getCompanyId(req);
    const vehicle = await fetchVehicleById(pool, req.params.id, companyId);

    if (!vehicle) {
      throw new ApiError(404, "Véhicule introuvable.");
    }

    const costs = await fetchCosts(pool, vehicle.id, req.query.period_from, req.query.period_to);
    res.json({ item: vehicle, costs });
  },

  async createVehicle(req, res) {
    const companyId = getCompanyId(req);
    const payload = buildVehiclePayload({ ...req.body, company_id: companyId });

    if (!payload.reference || !payload.plate_number) {
      throw new ApiError(400, "Référence et immatriculation sont obligatoires.");
    }

    const client = await pool.connect();
    try {
      await client.query("BEGIN");
      await ensureVehicleAssignmentTables(client);
      const selectedDriver = await resolveDriverSelection(client, companyId, payload.driver_id, payload.assigned_driver);
      payload.driver_id = selectedDriver.driverId;
      payload.assigned_driver = selectedDriver.driverName;
      const { rows } = await client.query(
        `
          INSERT INTO mgx_vehicles (
            company_id, depot_id, reference, code_camion, plate_number, brand, model, category_ref_id,
            year, chassis_number, fuel_type_ref_id, status_ref_id, km_initial, km_current,
            hour_counter, acquisition_date, acquisition_value, driver_id, assigned_driver,
            observations, photo_url, is_active, created_by
          )
          VALUES (
            $1, $2, $3, $4, $5, $6, $7, $8,
            $9, $10, $11, $12, $13, $14,
            $15, $16, $17, $18, $19,
            $20, $21, $22, $23
          )
          RETURNING *
        `,
        [
          payload.company_id,
          payload.depot_id,
          payload.reference,
          payload.code_camion,
          payload.plate_number,
          payload.brand,
          payload.model,
          payload.category_ref_id,
          payload.year,
          payload.chassis_number,
          payload.fuel_type_ref_id,
          payload.status_ref_id,
          payload.km_initial,
          payload.km_current,
          payload.hour_counter,
          payload.acquisition_date,
          payload.acquisition_value,
          payload.driver_id,
          payload.assigned_driver,
          payload.observations,
          payload.photo_url,
          payload.is_active,
          req.user?.sub || null,
        ],
      );

      const vehicle = rows[0];
      const initialStartDate = payload.acquisition_date || todayIso();

      if (payload.assigned_driver) {
        await insertDriverAssignment(client, req, {
          companyId,
          vehicleId: vehicle.id,
          driverId: payload.driver_id,
          driverName: payload.assigned_driver,
          startDate: payload.driver_start_date || initialStartDate,
          endDate: payload.driver_end_date,
          notes: payload.assignment_notes,
        });
      }

      if (payload.depot_id) {
        await insertDepotAssignment(client, req, {
          companyId,
          vehicleId: vehicle.id,
          depotId: payload.depot_id,
          startDate: payload.depot_start_date || initialStartDate,
          endDate: payload.depot_end_date,
          notes: payload.assignment_notes,
        });
      }

      if (payload.km_current !== null) {
        await client.query(
          `
            INSERT INTO mgx_vehicle_km_history (
              vehicle_id, km_value, reading_date, source, notes, created_by
            )
            VALUES ($1, $2, CURRENT_DATE, 'creation', 'Kilométrage initial véhicule', $3)
          `,
          [vehicle.id, payload.km_current, req.user?.sub || null],
        );
      }

      await logMgxAudit(client, req, {
        companyId,
        action: "CREATE",
        entityType: "mgx_vehicle",
        entityId: vehicle.id,
        newData: vehicle,
      });
      await client.query("COMMIT");

      const created = await fetchVehicleById(pool, vehicle.id, companyId);
      triggerAlertEngine(req, companyId);
      res.status(201).json({ item: created });
    } catch (error) {
      await client.query("ROLLBACK");
      if (error.code === "23505") {
        throw new ApiError(409, "Référence ou immatriculation déjà utilisée.");
      }
      throw error;
    } finally {
      client.release();
    }
  },

  async updateVehicle(req, res) {
    const companyId = getCompanyId(req);
    const payload = buildVehiclePayload({ ...req.body, company_id: companyId });
    const client = await pool.connect();

    try {
      await client.query("BEGIN");
      await ensureVehicleAssignmentTables(client);
      const oldVehicle = await fetchVehicleById(client, req.params.id, companyId);
      if (!oldVehicle) {
        throw new ApiError(404, "Véhicule introuvable.");
      }
      const selectedDriver = await resolveDriverSelection(client, companyId, payload.driver_id, payload.assigned_driver);
      payload.driver_id = selectedDriver.driverId;
      payload.assigned_driver = selectedDriver.driverName;

      const { rows } = await client.query(
        `
          UPDATE mgx_vehicles
          SET
            depot_id = $1,
            reference = $2,
            code_camion = $3,
            plate_number = $4,
            brand = $5,
            model = $6,
            category_ref_id = $7,
            year = $8,
            chassis_number = $9,
            fuel_type_ref_id = $10,
            status_ref_id = $11,
            km_initial = $12,
            km_current = $13,
            hour_counter = $14,
            acquisition_date = $15,
            acquisition_value = $16,
            driver_id = $17,
            assigned_driver = $18,
            observations = $19,
            photo_url = $20,
            is_active = $21,
            updated_at = NOW()
          WHERE id = $22
            AND company_id = $23
          RETURNING *
        `,
        [
          payload.depot_id,
          payload.reference,
          payload.code_camion,
          payload.plate_number,
          payload.brand,
          payload.model,
          payload.category_ref_id,
          payload.year,
          payload.chassis_number,
          payload.fuel_type_ref_id,
          payload.status_ref_id,
          payload.km_initial,
          payload.km_current,
          payload.hour_counter,
          payload.acquisition_date,
          payload.acquisition_value,
          payload.driver_id,
          payload.assigned_driver,
          payload.observations,
          payload.photo_url,
          payload.is_active,
          req.params.id,
          companyId,
        ],
      );

      if (Number(oldVehicle.km_current) !== Number(payload.km_current)) {
        await client.query(
          `
            INSERT INTO mgx_vehicle_km_history (
              vehicle_id, km_value, reading_date, source, notes, created_by
            )
            VALUES ($1, $2, CURRENT_DATE, 'manual', 'Mise à jour depuis fiche véhicule', $3)
          `,
          [req.params.id, payload.km_current, req.user?.sub || null],
        );
      }

      const assignmentStartDate = payload.driver_start_date || todayIso();
      if (Number(oldVehicle.driver_id || 0) !== Number(payload.driver_id || 0) || (oldVehicle.assigned_driver || "") !== (payload.assigned_driver || "")) {
        if (payload.assigned_driver) {
          await insertDriverAssignment(client, req, {
            companyId,
            vehicleId: req.params.id,
            driverId: payload.driver_id,
            driverName: payload.assigned_driver,
            startDate: assignmentStartDate,
            endDate: payload.driver_end_date,
            notes: payload.assignment_notes || "Changement depuis fiche véhicule",
          });
        } else {
          await closeActiveDriverAssignment(client, req.params.id, assignmentStartDate);
        }
      }

      const depotStartDate = payload.depot_start_date || todayIso();
      if (Number(oldVehicle.depot_id || 0) !== Number(payload.depot_id || 0)) {
        if (payload.depot_id) {
          await insertDepotAssignment(client, req, {
            companyId,
            vehicleId: req.params.id,
            depotId: payload.depot_id,
            startDate: depotStartDate,
            endDate: payload.depot_end_date,
            notes: payload.assignment_notes || "Transfert depuis fiche véhicule",
          });
        } else {
          await closeActiveDepotAssignment(client, req.params.id, depotStartDate);
        }
      }

      await logMgxAudit(client, req, {
        companyId,
        action: "UPDATE",
        entityType: "mgx_vehicle",
        entityId: req.params.id,
        oldData: oldVehicle,
        newData: rows[0],
      });
      await client.query("COMMIT");

      const updated = await fetchVehicleById(pool, req.params.id, companyId);
      triggerAlertEngine(req, companyId);
      res.json({ item: updated });
    } catch (error) {
      await client.query("ROLLBACK");
      if (error.code === "23505") {
        throw new ApiError(409, "Référence ou immatriculation déjà utilisée.");
      }
      throw error;
    } finally {
      client.release();
    }
  },

  async deleteVehicle(req, res) {
    const companyId = getCompanyId(req);
    const client = await pool.connect();

    try {
      await client.query("BEGIN");
      const oldVehicle = await fetchVehicleById(client, req.params.id, companyId);
      if (!oldVehicle) {
        throw new ApiError(404, "Véhicule introuvable.");
      }

      const { rows: usageRows } = await client.query(
        `
          SELECT
            (SELECT COUNT(*) FROM mgx_vehicle_documents WHERE vehicle_id = $1 AND status = 'active') +
            (SELECT COUNT(*) FROM mgx_fuel_entries WHERE vehicle_id = $1) +
            (SELECT COUNT(*) FROM mgx_interventions WHERE vehicle_id = $1) +
            (SELECT COUNT(*) FROM mgx_services WHERE vehicle_id = $1) +
            (SELECT COUNT(*) FROM mgx_rentals WHERE vehicle_id = $1) AS usage_count
        `,
        [req.params.id],
      );

      if (Number(usageRows[0]?.usage_count || 0) > 0) {
        throw new ApiError(409, "Impossible de supprimer un véhicule avec documents actifs ou historique.");
      }

      const { rows } = await client.query(
        `
          UPDATE mgx_vehicles
          SET is_active = false, updated_at = NOW()
          WHERE id = $1
            AND company_id = $2
          RETURNING *
        `,
        [req.params.id, companyId],
      );

      await logMgxAudit(client, req, {
        companyId,
        action: "DELETE",
        entityType: "mgx_vehicle",
        entityId: req.params.id,
        oldData: oldVehicle,
        newData: rows[0],
      });
      await client.query("COMMIT");
      triggerAlertEngine(req, companyId);
      res.json({ item: rows[0] });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },

  async updateKm(req, res) {
    const companyId = getCompanyId(req);
    const kmValue = nullableNumber(req.body.km_value);
    const readingDate = nullableString(req.body.reading_date) || new Date().toISOString().slice(0, 10);
    const readingTypeRefId = nullableNumber(req.body.reading_type_ref_id);

    if (kmValue === null || kmValue < 0) {
      throw new ApiError(400, "Kilométrage invalide.");
    }

    const client = await pool.connect();
    try {
      await client.query("BEGIN");
      const oldVehicle = await fetchVehicleById(client, req.params.id, companyId);
      if (!oldVehicle) {
        throw new ApiError(404, "Véhicule introuvable.");
      }

      await client.query(
        `
          INSERT INTO mgx_vehicle_km_history (
            vehicle_id, km_value, reading_date, reading_type_ref_id, source, notes, created_by
          )
          VALUES ($1, $2, $3, $4, 'manual', $5, $6)
        `,
        [
          req.params.id,
          kmValue,
          readingDate,
          readingTypeRefId,
          nullableString(req.body.notes),
          resolveActorUserId(req),
        ],
      );

      const { rows } = await client.query(
        `
          UPDATE mgx_vehicles
          SET km_current = $1, updated_at = NOW()
          WHERE id = $2
            AND company_id = $3
          RETURNING *
        `,
        [kmValue, req.params.id, companyId],
      );

      await logMgxAudit(client, req, {
        companyId,
        action: "UPDATE_KM",
        entityType: "mgx_vehicle",
        entityId: req.params.id,
        oldData: { km_current: oldVehicle.km_current },
        newData: { km_current: kmValue, reading_date: readingDate, vehicle: rows[0] },
      });
      await client.query("COMMIT");

      const updated = await fetchVehicleById(pool, req.params.id, companyId);
      triggerAlertEngine(req, companyId);
      res.json({ item: updated });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },

  async getVehicleCosts(req, res) {
    const companyId = getCompanyId(req);
    const vehicle = await fetchVehicleById(pool, req.params.id, companyId);
    if (!vehicle) {
      throw new ApiError(404, "Véhicule introuvable.");
    }

    const costs = await fetchCosts(pool, req.params.id, req.query.period_from, req.query.period_to);
    res.json(costs);
  },

  async getVehicleHistory(req, res) {
    const companyId = getCompanyId(req);
    const type = cleanString(req.query.type || "fuel");
    await ensureVehicleAssignmentTables();
    const vehicle = await fetchVehicleById(pool, req.params.id, companyId);

    if (!vehicle) {
      throw new ApiError(404, "Véhicule introuvable.");
    }

    const queries = {
      fuel: {
        sql: `
          SELECT
            f.id,
            f.entry_date AS date,
            fuel.label AS type_label,
            f.quantity,
            f.total_amount AS amount,
            f.km_at_fillup AS km,
            f.station_supplier AS reference,
            f.is_anomaly
          FROM mgx_fuel_entries f
          LEFT JOIN mgx_referentiels fuel ON fuel.id = f.fuel_type_ref_id
          WHERE f.vehicle_id = $1
          ORDER BY f.entry_date DESC, f.id DESC
          LIMIT 100
        `,
      },
      maintenance: {
        sql: `
          SELECT
            i.id,
            i.start_date AS date,
            mt.label AS type_label,
            i.label,
            i.total_cost AS amount,
            i.km_at_intervention AS km,
            i.invoice_number AS reference,
            status.label AS status_label
          FROM mgx_interventions i
          LEFT JOIN mgx_referentiels mt ON mt.id = i.maintenance_type_ref_id
          LEFT JOIN mgx_referentiels status ON status.id = i.status_ref_id
          WHERE i.vehicle_id = $1
          ORDER BY i.start_date DESC, i.id DESC
          LIMIT 100
        `,
      },
      services: {
        sql: `
          SELECT
            s.id,
            s.service_date AS date,
            st.label AS type_label,
            s.label,
            s.amount,
            NULL::numeric AS km,
            s.invoice_number AS reference,
            s.payment_status AS status_label
          FROM mgx_services s
          LEFT JOIN mgx_referentiels st ON st.id = s.service_type_ref_id
          WHERE s.vehicle_id = $1
          ORDER BY s.service_date DESC, s.id DESC
          LIMIT 100
        `,
      },
      km: {
        sql: `
          SELECT
            k.id,
            k.reading_date AS date,
            kt.label AS type_label,
            k.notes AS label,
            NULL::numeric AS amount,
            k.km_value AS km,
            k.source AS reference,
            NULL::text AS status_label
          FROM mgx_vehicle_km_history k
          LEFT JOIN mgx_referentiels kt ON kt.id = k.reading_type_ref_id
          WHERE k.vehicle_id = $1
          ORDER BY k.reading_date DESC, k.id DESC
          LIMIT 100
        `,
      },
      drivers: {
        sql: `
          SELECT
            da.id,
            da.start_date AS date,
            'Chauffeur' AS type_label,
            da.driver_name AS label,
            NULL::numeric AS amount,
            NULL::numeric AS km,
            da.notes AS reference,
            CASE WHEN da.end_date IS NULL THEN 'En cours' ELSE 'Terminé' END AS status_label,
            da.start_date,
            da.end_date,
            da.driver_id,
            da.driver_name,
            dr.code AS driver_code
          FROM mgx_vehicle_driver_assignments da
          LEFT JOIN mgx_drivers dr ON dr.id = da.driver_id
          WHERE da.vehicle_id = $1
          ORDER BY da.start_date DESC, da.id DESC
          LIMIT 100
        `,
      },
      depots: {
        sql: `
          SELECT
            va.id,
            va.start_date AS date,
            'Dépôt' AS type_label,
            depot.label AS label,
            NULL::numeric AS amount,
            NULL::numeric AS km,
            va.notes AS reference,
            CASE WHEN va.end_date IS NULL THEN 'En cours' ELSE 'Terminé' END AS status_label,
            va.start_date,
            va.end_date,
            depot.label AS depot_label
          FROM mgx_vehicle_depot_assignments va
          LEFT JOIN mgx_depots depot ON depot.id = va.depot_id
          WHERE va.vehicle_id = $1
          ORDER BY va.start_date DESC, va.id DESC
          LIMIT 100
        `,
      },
      rentals: {
        sql: `
          SELECT
            r.id,
            r.start_date AS date,
            status.label AS type_label,
            r.rental_type AS label,
            r.total_amount AS amount,
            NULL::numeric AS km,
            supplier.name AS reference,
            status.label AS status_label
          FROM mgx_rentals r
          LEFT JOIN mgx_referentiels status ON status.id = r.status_ref_id
          LEFT JOIN mgx_suppliers supplier ON supplier.id = r.supplier_id
          WHERE r.vehicle_id = $1
          ORDER BY r.start_date DESC, r.id DESC
          LIMIT 100
        `,
      },
    };

    if (!queries[type]) {
      throw new ApiError(400, "Type d'historique invalide.");
    }

    const { rows } = await pool.query(queries[type].sql, [req.params.id]);
    res.json({
      items: rows.map((row) => ({
        ...row,
        id: Number(row.id),
        amount: row.amount === null ? null : toNumber(row.amount),
        amount_formatted: row.amount === null ? "—" : formatDzdAmount(row.amount),
        km: row.km === null ? null : toNumber(row.km),
      })),
    });
  },

  async assignDriver(req, res) {
    const companyId = getCompanyId(req);
    const driverId = nullableNumber(req.body.driver_id);
    const fallbackDriverName = nullableString(req.body.driver_name);
    const startDate = isoDateOnly(req.body.start_date) || todayIso();
    const endDate = isoDateOnly(req.body.end_date);
    const notes = nullableString(req.body.notes);

    const client = await pool.connect();
    try {
      await client.query("BEGIN");
      await ensureVehicleAssignmentTables(client);
      const { driverId: selectedDriverId, driverName } = await resolveDriverSelection(
        client,
        companyId,
        driverId,
        fallbackDriverName,
      );
      if (!driverName) {
        throw new ApiError(400, "Chauffeur requis.");
      }
      const vehicle = await fetchVehicleById(client, req.params.id, companyId);
      if (!vehicle) {
        throw new ApiError(404, "Véhicule introuvable.");
      }

      const assignment = await insertDriverAssignment(client, req, {
        companyId,
        vehicleId: req.params.id,
        driverId: selectedDriverId,
        driverName,
        startDate,
        endDate,
        notes,
      });

      await client.query(
        `
          UPDATE mgx_vehicles
          SET driver_id = $1, assigned_driver = $2, updated_at = NOW()
          WHERE id = $3 AND company_id = $4
        `,
        [selectedDriverId, driverName, req.params.id, companyId],
      );

      await logMgxAudit(client, req, {
        companyId,
        action: "ASSIGN_DRIVER",
        entityType: "mgx_vehicle",
        entityId: req.params.id,
        oldData: { driver_id: vehicle.driver_id, assigned_driver: vehicle.assigned_driver },
        newData: assignment,
      });
      await client.query("COMMIT");

      const updated = await fetchVehicleById(pool, req.params.id, companyId);
      res.status(201).json({ item: updated, assignment: mapDriverAssignment(assignment) });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },

  async unassignDriver(req, res) {
    const companyId = getCompanyId(req);
    const endDate = isoDateOnly(req.body.end_date) || todayIso();
    const notes = nullableString(req.body.notes);

    const client = await pool.connect();
    try {
      await client.query("BEGIN");
      await ensureVehicleAssignmentTables(client);
      const vehicle = await fetchVehicleById(client, req.params.id, companyId);
      if (!vehicle) {
        throw new ApiError(404, "Véhicule introuvable.");
      }

      await client.query(
        `
          UPDATE mgx_vehicle_driver_assignments
          SET
            end_date = COALESCE(end_date, $2::date),
            notes = CASE
              WHEN $3::text IS NULL OR $3::text = '' THEN notes
              WHEN notes IS NULL OR notes = '' THEN $3::text
              ELSE notes || E'\n' || $3::text
            END,
            updated_at = NOW()
          WHERE vehicle_id = $1
            AND end_date IS NULL
        `,
        [req.params.id, endDate, notes],
      );

      await client.query(
        `
          UPDATE mgx_vehicles
          SET driver_id = NULL, assigned_driver = NULL, updated_at = NOW()
          WHERE id = $1 AND company_id = $2
        `,
        [req.params.id, companyId],
      );

      await logMgxAudit(client, req, {
        companyId,
        action: "UNASSIGN_DRIVER",
        entityType: "mgx_vehicle",
        entityId: req.params.id,
        oldData: { driver_id: vehicle.driver_id, assigned_driver: vehicle.assigned_driver },
        newData: { driver_id: null, assigned_driver: null, end_date: endDate, notes },
      });
      await client.query("COMMIT");

      const updated = await fetchVehicleById(pool, req.params.id, companyId);
      res.json({ item: updated });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },

  async transferDepot(req, res) {
    const companyId = getCompanyId(req);
    const depotId = nullableNumber(req.body.depot_id);
    const startDate = isoDateOnly(req.body.start_date) || todayIso();
    const endDate = isoDateOnly(req.body.end_date);
    const notes = nullableString(req.body.notes);

    if (!depotId) {
      throw new ApiError(400, "Dépôt requis.");
    }

    const client = await pool.connect();
    try {
      await client.query("BEGIN");
      await ensureVehicleAssignmentTables(client);
      const vehicle = await fetchVehicleById(client, req.params.id, companyId);
      if (!vehicle) {
        throw new ApiError(404, "Véhicule introuvable.");
      }

      const { rows: depotRows } = await client.query(
        "SELECT * FROM mgx_depots WHERE id = $1 AND is_active = true",
        [depotId],
      );
      if (!depotRows[0]) {
        throw new ApiError(404, "Dépôt introuvable.");
      }

      const assignment = await insertDepotAssignment(client, req, {
        companyId,
        vehicleId: req.params.id,
        depotId,
        startDate,
        endDate,
        notes,
      });

      await client.query(
        `
          UPDATE mgx_vehicles
          SET depot_id = $1, updated_at = NOW()
          WHERE id = $2 AND company_id = $3
        `,
        [depotId, req.params.id, companyId],
      );

      await logMgxAudit(client, req, {
        companyId,
        action: "TRANSFER_DEPOT",
        entityType: "mgx_vehicle",
        entityId: req.params.id,
        oldData: { depot_id: vehicle.depot_id },
        newData: assignment,
      });
      await client.query("COMMIT");

      const updated = await fetchVehicleById(pool, req.params.id, companyId);
      res.status(201).json({
        item: updated,
        assignment: mapDepotAssignment({
          ...assignment,
          depot_code: depotRows[0].code,
          depot_label: depotRows[0].label,
          depot_city: depotRows[0].city,
        }),
      });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },

  async listDocuments(req, res) {
    const companyId = getCompanyId(req);
    const vehicleId = nullableNumber(req.query.vehicle_id);

    if (!vehicleId) {
      throw new ApiError(400, "Véhicule requis.");
    }

    const { rows } = await pool.query(
      `
        ${documentSelect}
        WHERE doc.company_id = $1
          AND doc.vehicle_id = $2
        ORDER BY doc.expiry_date ASC, doc.id DESC
      `,
      [companyId, vehicleId],
    );

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

  async createDocument(req, res) {
    const companyId = getCompanyId(req);
    const payload = {
      vehicle_id: nullableNumber(req.body.vehicle_id),
      document_type_ref_id: nullableNumber(req.body.document_type_ref_id),
      reference_number: nullableString(req.body.reference_number),
      issuer: nullableString(req.body.issuer),
      start_date: nullableString(req.body.start_date),
      expiry_date: nullableString(req.body.expiry_date),
      amount: nullableNumber(req.body.amount),
      file_url: nullableString(req.body.file_url),
      notes: nullableString(req.body.notes),
      status: nullableString(req.body.status) || "active",
      alert_days_before: toNumber(req.body.alert_days_before, 30),
    };

    if (!payload.vehicle_id || !payload.document_type_ref_id || !payload.expiry_date) {
      throw new ApiError(400, "Type de document, véhicule et date d'échéance sont obligatoires.");
    }

    const client = await pool.connect();
    try {
      await client.query("BEGIN");
      const { rows } = await client.query(
        `
          INSERT INTO mgx_vehicle_documents (
            vehicle_id, company_id, document_type_ref_id, reference_number, issuer,
            start_date, expiry_date, amount, file_url, notes, status, alert_days_before, created_by
          )
          VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
          RETURNING *
        `,
        [
          payload.vehicle_id,
          companyId,
          payload.document_type_ref_id,
          payload.reference_number,
          payload.issuer,
          payload.start_date,
          payload.expiry_date,
          payload.amount,
          payload.file_url,
          payload.notes,
          payload.status,
          payload.alert_days_before,
          req.user?.sub || null,
        ],
      );

      await logMgxAudit(client, req, {
        companyId,
        action: "CREATE",
        entityType: "mgx_vehicle_document",
        entityId: rows[0].id,
        newData: rows[0],
      });
      await client.query("COMMIT");
      triggerAlertEngine(req, companyId);
      res.status(201).json({ item: rows[0] });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },

  async updateDocument(req, res) {
    const companyId = getCompanyId(req);
    const client = await pool.connect();

    try {
      await client.query("BEGIN");
      const { rows: oldRows } = await client.query(
        "SELECT * FROM mgx_vehicle_documents WHERE id = $1 AND company_id = $2",
        [req.params.id, companyId],
      );
      if (!oldRows[0]) {
        throw new ApiError(404, "Document introuvable.");
      }

      const payload = {
        document_type_ref_id: nullableNumber(req.body.document_type_ref_id),
        reference_number: nullableString(req.body.reference_number),
        issuer: nullableString(req.body.issuer),
        start_date: nullableString(req.body.start_date),
        expiry_date: nullableString(req.body.expiry_date),
        amount: nullableNumber(req.body.amount),
        file_url: nullableString(req.body.file_url),
        notes: nullableString(req.body.notes),
        status: nullableString(req.body.status) || "active",
        alert_days_before: toNumber(req.body.alert_days_before, 30),
      };

      const { rows } = await client.query(
        `
          UPDATE mgx_vehicle_documents
          SET
            document_type_ref_id = $1,
            reference_number = $2,
            issuer = $3,
            start_date = $4,
            expiry_date = $5,
            amount = $6,
            file_url = $7,
            notes = $8,
            status = $9,
            alert_days_before = $10,
            updated_at = NOW()
          WHERE id = $11
            AND company_id = $12
          RETURNING *
        `,
        [
          payload.document_type_ref_id,
          payload.reference_number,
          payload.issuer,
          payload.start_date,
          payload.expiry_date,
          payload.amount,
          payload.file_url,
          payload.notes,
          payload.status,
          payload.alert_days_before,
          req.params.id,
          companyId,
        ],
      );

      await logMgxAudit(client, req, {
        companyId,
        action: "UPDATE",
        entityType: "mgx_vehicle_document",
        entityId: req.params.id,
        oldData: oldRows[0],
        newData: rows[0],
      });
      await client.query("COMMIT");
      triggerAlertEngine(req, companyId);
      res.json({ item: rows[0] });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },

  async deleteDocument(req, res) {
    const companyId = getCompanyId(req);
    const client = await pool.connect();

    try {
      await client.query("BEGIN");
      const { rows: oldRows } = await client.query(
        "SELECT * FROM mgx_vehicle_documents WHERE id = $1 AND company_id = $2",
        [req.params.id, companyId],
      );
      if (!oldRows[0]) {
        throw new ApiError(404, "Document introuvable.");
      }

      await client.query(
        "DELETE FROM mgx_vehicle_documents WHERE id = $1 AND company_id = $2",
        [req.params.id, companyId],
      );

      await logMgxAudit(client, req, {
        companyId,
        action: "DELETE",
        entityType: "mgx_vehicle_document",
        entityId: req.params.id,
        oldData: oldRows[0],
      });
      await client.query("COMMIT");
      triggerAlertEngine(req, companyId);
      res.json({ ok: true });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },
};
