import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken";

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

const PASSWORD_SALT_ROUNDS = 12;

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 normalizeEmail = (value) => cleanString(value).toLowerCase();

const STAFF_ROLE_TYPES = new Set(["chef_parc", "mecanicien", "back_office", "controleur_mgx"]);
const MOBILE_ROLE_TYPES = new Set(["chauffeur", "chef_parc", "mecanicien", "back_office", "controleur_mgx"]);

const MOBILE_ROLE_LABELS = {
  chauffeur: "Chauffeur",
  chef_parc: "Chef de parc",
  mecanicien: "Mécanicien",
  back_office: "Back Office",
  controleur_mgx: "Contrôleur MGX",
};

const signMobileQrLoginToken = (row) =>
  jwt.sign(
    {
      purpose: "mgx_mobile_qr_login",
      mobileAccountId: Number(row.id),
      companyId: Number(row.company_id),
      role_type: row.role_type,
      email: row.email,
    },
    env.jwtSecret,
    { expiresIn: "15m" },
  );

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 ensureValidStaffRole = (roleType) => {
  if (!STAFF_ROLE_TYPES.has(roleType)) {
    throw new ApiError(400, "Type de personnel invalide.");
  }
};

const ensureValidMobileRole = (roleType) => {
  if (!MOBILE_ROLE_TYPES.has(roleType)) {
    throw new ApiError(400, "Type de compte mobile invalide.");
  }
};

export const ensureMgxStaffMobileTables = async (db = pool) => {
  await db.query(`
    CREATE TABLE IF NOT EXISTS mgx_staff_profiles (
      id BIGSERIAL PRIMARY KEY,
      company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
      depot_id BIGINT REFERENCES mgx_depots (id) ON DELETE SET NULL,
      role_type VARCHAR(30) NOT NULL,
      code VARCHAR(50) NOT NULL,
      full_name VARCHAR(200) NOT NULL,
      phone VARCHAR(50),
      notes TEXT,
      is_active BOOLEAN NOT NULL DEFAULT TRUE,
      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 uq_mgx_staff_profiles_company_role_code UNIQUE (company_id, role_type, code),
      CONSTRAINT chk_mgx_staff_profiles_role_type CHECK (role_type IN ('chef_parc', 'mecanicien', 'back_office', 'controleur_mgx'))
    )
  `);

  await db.query(`
    CREATE TABLE IF NOT EXISTS mgx_mobile_accounts (
      id BIGSERIAL PRIMARY KEY,
      company_id BIGINT NOT NULL REFERENCES companies (id) ON DELETE CASCADE,
      role_type VARCHAR(30) NOT NULL,
      driver_id BIGINT REFERENCES mgx_drivers (id) ON DELETE CASCADE,
      staff_profile_id BIGINT REFERENCES mgx_staff_profiles (id) ON DELETE CASCADE,
      email VARCHAR(200) NOT NULL,
      password_hash TEXT NOT NULL,
      is_active BOOLEAN NOT NULL DEFAULT TRUE,
      failed_login_attempts INTEGER NOT NULL DEFAULT 0,
      locked_at TIMESTAMPTZ,
      last_login TIMESTAMPTZ,
      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_mobile_accounts_role_type CHECK (role_type IN ('chauffeur', 'chef_parc', 'mecanicien', 'back_office', 'controleur_mgx')),
      CONSTRAINT chk_mgx_mobile_accounts_link CHECK (
        (role_type = 'chauffeur' AND driver_id IS NOT NULL AND staff_profile_id IS NULL)
        OR
        (role_type <> 'chauffeur' AND driver_id IS NULL AND staff_profile_id IS NOT NULL)
      )
    )
  `);

  await db.query(`
    DO $$
    BEGIN
      ALTER TABLE mgx_staff_profiles
        DROP CONSTRAINT IF EXISTS chk_mgx_staff_profiles_role_type;

      ALTER TABLE mgx_staff_profiles
        ADD CONSTRAINT chk_mgx_staff_profiles_role_type
        CHECK (role_type IN ('chef_parc', 'mecanicien', 'back_office', 'controleur_mgx'));
    END $$;
  `);
  await db.query(`
    DO $$
    BEGIN
      ALTER TABLE mgx_mobile_accounts
        DROP CONSTRAINT IF EXISTS chk_mgx_mobile_accounts_role_type;

      ALTER TABLE mgx_mobile_accounts
        ADD CONSTRAINT chk_mgx_mobile_accounts_role_type
        CHECK (role_type IN ('chauffeur', 'chef_parc', 'mecanicien', 'back_office', 'controleur_mgx'));
    END $$;
  `);

  await db.query(`
    CREATE UNIQUE INDEX IF NOT EXISTS uq_mgx_mobile_accounts_email
      ON mgx_mobile_accounts (LOWER(email))
  `);
  await db.query(`
    CREATE UNIQUE INDEX IF NOT EXISTS uq_mgx_mobile_accounts_driver_id
      ON mgx_mobile_accounts (driver_id)
      WHERE driver_id IS NOT NULL
  `);
  await db.query(`
    CREATE UNIQUE INDEX IF NOT EXISTS uq_mgx_mobile_accounts_staff_profile_id
      ON mgx_mobile_accounts (staff_profile_id)
      WHERE staff_profile_id IS NOT NULL
  `);
  await db.query(`
    CREATE INDEX IF NOT EXISTS idx_mgx_staff_profiles_company_role_active
      ON mgx_staff_profiles (company_id, role_type, is_active)
  `);
  await db.query(`
    CREATE INDEX IF NOT EXISTS idx_mgx_mobile_accounts_company_role_active
      ON mgx_mobile_accounts (company_id, role_type, is_active)
  `);
};

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

const staffSelect = `
  SELECT
    sp.*,
    c.name AS company_name,
    d.code AS depot_code,
    d.label AS depot_label,
    d.city AS depot_city
  FROM mgx_staff_profiles sp
  LEFT JOIN companies c ON c.id = sp.company_id
  LEFT JOIN mgx_depots d ON d.id = sp.depot_id
`;

const mapStaffProfile = (row) => ({
  id: Number(row.id),
  company_id: Number(row.company_id),
  company: row.company_name ? { id: Number(row.company_id), name: row.company_name } : null,
  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,
  role_type: row.role_type,
  role_label: MOBILE_ROLE_LABELS[row.role_type] || row.role_type,
  code: row.code,
  full_name: row.full_name,
  phone: row.phone,
  notes: row.notes,
  is_active: row.is_active,
  created_at: row.created_at,
  updated_at: row.updated_at,
});

const mobileAccountSelect = `
  SELECT
    ma.*,
    c.name AS company_name,
    dr.code AS driver_code,
    dr.full_name AS driver_full_name,
    dr.phone AS driver_phone,
    dr.depot_id AS driver_depot_id,
    dd.code AS driver_depot_code,
    dd.label AS driver_depot_label,
    sp.code AS staff_code,
    sp.full_name AS staff_full_name,
    sp.phone AS staff_phone,
    sp.depot_id AS staff_depot_id,
    sd.code AS staff_depot_code,
    sd.label AS staff_depot_label
  FROM mgx_mobile_accounts ma
  LEFT JOIN companies c ON c.id = ma.company_id
  LEFT JOIN mgx_drivers dr ON dr.id = ma.driver_id
  LEFT JOIN mgx_depots dd ON dd.id = dr.depot_id
  LEFT JOIN mgx_staff_profiles sp ON sp.id = ma.staff_profile_id
  LEFT JOIN mgx_depots sd ON sd.id = sp.depot_id
`;

const mapMobileAccount = (row) => {
  const isDriver = row.role_type === "chauffeur";
  const linkedId = isDriver ? row.driver_id : row.staff_profile_id;
  const linkedDepotId = isDriver ? row.driver_depot_id : row.staff_depot_id;
  const linkedDepotCode = isDriver ? row.driver_depot_code : row.staff_depot_code;
  const linkedDepotLabel = isDriver ? row.driver_depot_label : row.staff_depot_label;
  const linkedCode = isDriver ? row.driver_code : row.staff_code;
  const linkedName = isDriver ? row.driver_full_name : row.staff_full_name;
  const linkedPhone = isDriver ? row.driver_phone : row.staff_phone;

  return {
    id: Number(row.id),
    company_id: Number(row.company_id),
    company_name: row.company_name || null,
    role_type: row.role_type,
    role_label: MOBILE_ROLE_LABELS[row.role_type] || row.role_type,
    email: row.email,
    is_active: row.is_active,
    last_login: row.last_login,
    linked_entity_id: linkedId ? Number(linkedId) : null,
    linked_entity_type: isDriver ? "driver" : "staff_profile",
    linked_entity_code: linkedCode || null,
    linked_entity_name: linkedName || null,
    linked_entity_phone: linkedPhone || null,
    depot_id: linkedDepotId ? Number(linkedDepotId) : null,
    depot: linkedDepotId
      ? { id: Number(linkedDepotId), code: linkedDepotCode, label: linkedDepotLabel }
      : null,
    driver_id: row.driver_id ? Number(row.driver_id) : null,
    staff_profile_id: row.staff_profile_id ? Number(row.staff_profile_id) : null,
    created_at: row.created_at,
    updated_at: row.updated_at,
  };
};

const buildStaffPayload = (body) => {
  const roleType = cleanString(body.role_type || body.roleType).toLowerCase();
  ensureValidStaffRole(roleType);

  return {
    company_id: Number(body.company_id),
    depot_id: nullableNumber(body.depot_id),
    role_type: roleType,
    code: cleanString(body.code).toUpperCase(),
    full_name: cleanString(body.full_name),
    phone: nullableString(body.phone),
    notes: nullableString(body.notes),
    is_active: body.is_active !== false,
  };
};

const buildMobileAccountPayload = (body) => {
  const roleType = cleanString(body.role_type || body.roleType).toLowerCase();
  ensureValidMobileRole(roleType);

  return {
    company_id: Number(body.company_id),
    role_type: roleType,
    driver_id: nullableNumber(body.driver_id),
    staff_profile_id: nullableNumber(body.staff_profile_id),
    email: normalizeEmail(body.email),
    password: String(body.password || ""),
    is_active: body.is_active !== false,
  };
};

const ensureRoleLinkExists = async (db, payload) => {
  if (payload.role_type === "chauffeur") {
    if (!payload.driver_id) {
      throw new ApiError(400, "Le chauffeur lié est obligatoire.");
    }

    const { rows } = await db.query(
      "SELECT id, company_id, is_active FROM mgx_drivers WHERE id = $1 LIMIT 1",
      [payload.driver_id],
    );
    const item = rows[0];
    if (!item || Number(item.company_id) !== Number(payload.company_id)) {
      throw new ApiError(404, "Chauffeur introuvable.");
    }
    return;
  }

  if (!payload.staff_profile_id) {
    throw new ApiError(400, "Le personnel lié est obligatoire.");
  }

  const { rows } = await db.query(
    "SELECT id, company_id, role_type, is_active FROM mgx_staff_profiles WHERE id = $1 LIMIT 1",
    [payload.staff_profile_id],
  );
  const item = rows[0];
  if (!item || Number(item.company_id) !== Number(payload.company_id) || item.role_type !== payload.role_type) {
    throw new ApiError(404, "Personnel introuvable.");
  }
};

export const mgxStaffProfilesController = {
  async list(req, res) {
    await ensureMgxStaffMobileTables();
    const roleType = cleanString(req.query.role_type || req.query.roleType).toLowerCase();
    ensureValidStaffRole(roleType);
    const allCompanies = req.query.all_companies === "true" || req.query.company_id === "all";
    const onlyActive = req.query.active === "true";
    const values = [roleType];
    const conditions = [`sp.role_type = $1`];

    if (!allCompanies) {
      values.push(getCompanyId(req));
      conditions.push(`sp.company_id = $${values.length}`);
    }
    if (onlyActive) {
      conditions.push("sp.is_active = TRUE");
    }

    const { rows } = await pool.query(
      `
        ${staffSelect}
        WHERE ${conditions.join(" AND ")}
        ORDER BY c.name ASC, sp.is_active DESC, sp.full_name ASC
      `,
      values,
    );

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

  async get(req, res) {
    await ensureMgxStaffMobileTables();
    const companyId = getCompanyId(req);
    const { rows } = await pool.query(
      `
        ${staffSelect}
        WHERE sp.id = $1 AND sp.company_id = $2
        LIMIT 1
      `,
      [req.params.id, companyId],
    );
    if (!rows[0]) {
      throw new ApiError(404, "Personnel introuvable.");
    }
    res.json({ item: mapStaffProfile(rows[0]) });
  },

  async save(req, res) {
    await ensureMgxStaffMobileTables();
    const payload = buildStaffPayload(req.body);
    if (!payload.company_id || !payload.code || !payload.full_name) {
      throw new ApiError(400, "Société, code et nom sont obligatoires.");
    }

    const client = await pool.connect();
    try {
      await client.query("BEGIN");
      let previous = null;
      let rows;

      if (req.params.id) {
        const previousResult = await client.query(
          "SELECT * FROM mgx_staff_profiles WHERE id = $1 AND company_id = $2",
          [req.params.id, payload.company_id],
        );
        previous = previousResult.rows[0];
        if (!previous) {
          throw new ApiError(404, "Personnel introuvable.");
        }

        ({ rows } = await client.query(
          `
            UPDATE mgx_staff_profiles
            SET
              depot_id = $3,
              role_type = $4,
              code = $5,
              full_name = $6,
              phone = $7,
              notes = $8,
              is_active = $9,
              updated_at = NOW()
            WHERE id = $1 AND company_id = $2
            RETURNING *
          `,
          [
            req.params.id,
            payload.company_id,
            payload.depot_id,
            payload.role_type,
            payload.code,
            payload.full_name,
            payload.phone,
            payload.notes,
            payload.is_active,
          ],
        ));
      } else {
        ({ rows } = await client.query(
          `
            INSERT INTO mgx_staff_profiles (
              company_id, depot_id, role_type, code, full_name, phone, notes, is_active, created_by
            )
            VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
            RETURNING *
          `,
          [
            payload.company_id,
            payload.depot_id,
            payload.role_type,
            payload.code,
            payload.full_name,
            payload.phone,
            payload.notes,
            payload.is_active,
            req.user?.sub || null,
          ],
        ));
      }

      const saved = rows[0];
      await logMgxAudit(client, req, {
        companyId: payload.company_id,
        action: req.params.id ? "mgx.staff_profiles.update" : "mgx.staff_profiles.create",
        entityType: "mgx_staff_profiles",
        entityId: saved.id,
        oldData: previous,
        newData: saved,
      });
      await client.query("COMMIT");
      res.status(req.params.id ? 200 : 201).json({
        item: mapStaffProfile({
          ...saved,
          company_name: null,
          depot_code: null,
          depot_label: null,
          depot_city: null,
        }),
      });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },

  async remove(req, res) {
    await ensureMgxStaffMobileTables();
    const companyId = getCompanyId(req);
    const client = await pool.connect();
    try {
      await client.query("BEGIN");
      const { rows } = await client.query(
        "SELECT * FROM mgx_staff_profiles WHERE id = $1 AND company_id = $2",
        [req.params.id, companyId],
      );
      const previous = rows[0];
      if (!previous) {
        throw new ApiError(404, "Personnel introuvable.");
      }

      await client.query(
        "UPDATE mgx_staff_profiles SET is_active = FALSE, updated_at = NOW() WHERE id = $1",
        [req.params.id],
      );
      await client.query(
        "UPDATE mgx_mobile_accounts SET is_active = FALSE, updated_at = NOW() WHERE staff_profile_id = $1",
        [req.params.id],
      );
      await logMgxAudit(client, req, {
        companyId,
        action: "mgx.staff_profiles.delete",
        entityType: "mgx_staff_profiles",
        entityId: previous.id,
        oldData: previous,
      });
      await client.query("COMMIT");
      res.json({ message: "Personnel désactivé." });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },
};

export const mgxMobileAccountsController = {
  async list(req, res) {
    await ensureMgxStaffMobileTables();
    const allCompanies = req.query.all_companies === "true" || req.query.company_id === "all";
    const roleType = cleanString(req.query.role_type || req.query.roleType).toLowerCase();
    const values = [];
    const conditions = [];
    if (roleType) {
      ensureValidMobileRole(roleType);
      values.push(roleType);
      conditions.push(`ma.role_type = $${values.length}`);
    }
    if (!allCompanies) {
      values.push(getCompanyId(req));
      conditions.push(`ma.company_id = $${values.length}`);
    }

    const { rows } = await pool.query(
      `
        ${mobileAccountSelect}
        ${conditions.length ? `WHERE ${conditions.join(" AND ")}` : ""}
        ORDER BY c.name ASC, ma.role_type ASC, COALESCE(dr.full_name, sp.full_name) ASC
      `,
      values,
    );
    res.json({ items: rows.map(mapMobileAccount) });
  },

  async get(req, res) {
    await ensureMgxStaffMobileTables();
    const companyId = getCompanyId(req);
    const { rows } = await pool.query(
      `
        ${mobileAccountSelect}
        WHERE ma.id = $1 AND ma.company_id = $2
        LIMIT 1
      `,
      [req.params.id, companyId],
    );
    if (!rows[0]) {
      throw new ApiError(404, "Compte mobile introuvable.");
    }
    res.json({ item: mapMobileAccount(rows[0]) });
  },

  async getQrLoginPayload(req, res) {
    await ensureMgxStaffMobileTables();

    const companyId = getCompanyId(req);
    const id = Number(req.params.id);
    if (!id) {
      throw new ApiError(400, "Compte mobile invalide.");
    }

    const { rows } = await pool.query(
      `${mobileAccountSelect} WHERE ma.id = $1 AND ma.company_id = $2 LIMIT 1`,
      [id, companyId],
    );

    const row = rows[0];
    if (!row) {
      throw new ApiError(404, "Compte mobile introuvable.");
    }

    const item = mapMobileAccount(row);

    res.json({
      item,
      qr_payload: {
        module: "MGX",
        role_type: item.role_type,
        role_label: item.role_label,
        server_url: `${req.protocol}://${req.get("host")}`,
        mobile_account_id: item.id,
        linked_entity_id: item.linked_entity_id,
        linked_entity_type: item.linked_entity_type,
        email: item.email,
        company_id: item.company_id,
        qr_login_token: signMobileQrLoginToken(row),
      },
    });
  },

  async save(req, res) {
    await ensureMgxStaffMobileTables();
    const payload = buildMobileAccountPayload(req.body);
    if (!payload.company_id || !payload.email) {
      throw new ApiError(400, "Société et e-mail sont obligatoires.");
    }

    const client = await pool.connect();
    try {
      await client.query("BEGIN");
      await ensureRoleLinkExists(client, payload);
      let previous = null;
      let rows;

      const { rows: duplicateRows } = await client.query(
        `SELECT id FROM mgx_mobile_accounts WHERE LOWER(email) = LOWER($1) AND ($2::bigint IS NULL OR id <> $2) LIMIT 1`,
        [payload.email, req.params.id ? Number(req.params.id) : null],
      );
      if (duplicateRows[0]) {
        throw new ApiError(409, "Cet e-mail existe déjà dans les comptes mobiles.");
      }

      if (req.params.id) {
        const previousResult = await client.query(
          "SELECT * FROM mgx_mobile_accounts WHERE id = $1 AND company_id = $2",
          [req.params.id, payload.company_id],
        );
        previous = previousResult.rows[0];
        if (!previous) {
          throw new ApiError(404, "Compte mobile introuvable.");
        }

        const passwordHash = payload.password
          ? await bcrypt.hash(payload.password, PASSWORD_SALT_ROUNDS)
          : previous.password_hash;

        ({ rows } = await client.query(
          `
            UPDATE mgx_mobile_accounts
            SET
              role_type = $3,
              driver_id = $4,
              staff_profile_id = $5,
              email = $6,
              password_hash = $7,
              is_active = $8,
              failed_login_attempts = CASE WHEN $9 THEN 0 ELSE failed_login_attempts END,
              locked_at = CASE WHEN $9 THEN NULL ELSE locked_at END,
              updated_at = NOW()
            WHERE id = $1 AND company_id = $2
            RETURNING *
          `,
          [
            req.params.id,
            payload.company_id,
            payload.role_type,
            payload.driver_id,
            payload.staff_profile_id,
            payload.email,
            passwordHash,
            payload.is_active,
            Boolean(payload.password) || payload.is_active,
          ],
        ));
      } else {
        if (!payload.password) {
          throw new ApiError(400, "Le mot de passe est obligatoire.");
        }
        const passwordHash = await bcrypt.hash(payload.password, PASSWORD_SALT_ROUNDS);

        ({ rows } = await client.query(
          `
            INSERT INTO mgx_mobile_accounts (
              company_id, role_type, driver_id, staff_profile_id, email, password_hash, is_active, created_by
            )
            VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
            RETURNING *
          `,
          [
            payload.company_id,
            payload.role_type,
            payload.driver_id,
            payload.staff_profile_id,
            payload.email,
            passwordHash,
            payload.is_active,
            req.user?.sub || null,
          ],
        ));
      }

      const saved = rows[0];
      await logMgxAudit(client, req, {
        companyId: payload.company_id,
        action: req.params.id ? "mgx.mobile_accounts.update" : "mgx.mobile_accounts.create",
        entityType: "mgx_mobile_accounts",
        entityId: saved.id,
        oldData: previous,
        newData: saved,
      });
      await client.query("COMMIT");
      const fullRows = await pool.query(
        `${mobileAccountSelect} WHERE ma.id = $1 LIMIT 1`,
        [saved.id],
      );
      res.status(req.params.id ? 200 : 201).json({ item: mapMobileAccount(fullRows.rows[0]) });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },

  async remove(req, res) {
    await ensureMgxStaffMobileTables();
    const companyId = getCompanyId(req);
    const client = await pool.connect();
    try {
      await client.query("BEGIN");
      const { rows } = await client.query(
        "SELECT * FROM mgx_mobile_accounts WHERE id = $1 AND company_id = $2",
        [req.params.id, companyId],
      );
      const previous = rows[0];
      if (!previous) {
        throw new ApiError(404, "Compte mobile introuvable.");
      }

      await client.query(
        "UPDATE mgx_mobile_accounts SET is_active = FALSE, updated_at = NOW() WHERE id = $1",
        [req.params.id],
      );
      await logMgxAudit(client, req, {
        companyId,
        action: "mgx.mobile_accounts.delete",
        entityType: "mgx_mobile_accounts",
        entityId: previous.id,
        oldData: previous,
      });
      await client.query("COMMIT");
      res.json({ message: "Compte mobile désactivé." });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },
};
