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

import { ApiError } from "../utils/ApiError.js";
import { logAudit } from "../utils/auditLog.js";
import { canManageAdmin, fetchRolePermissions } from "../utils/permissions.js";
import { ensureSystemSettings, normalizeSystemSettings } from "../utils/systemSettings.js";

const cleanString = (value) => String(value ?? "").trim();

const ensureAdminPermission = async (db, req) => {
  const permissions = await fetchRolePermissions(db, req.user?.role);

  if (!canManageAdmin(req.user?.role, permissions)) {
    throw new ApiError(403, "Accès refusé aux paramètres système.");
  }
};

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

    try {
      await client.query("BEGIN");
      await ensureAdminPermission(client, req);

      const item = await ensureSystemSettings(client);

      await client.query("COMMIT");

      res.json({ item });
    } catch (error) {
      await client.query("ROLLBACK");
      throw error;
    } finally {
      client.release();
    }
  },

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

    try {
      await client.query("BEGIN");
      await ensureAdminPermission(client, req);

      const currentSettings = await ensureSystemSettings(client);
      const payload = {
        application_name:
          cleanString(req.body.application_name) || currentSettings.application_name,
        default_language:
          cleanString(req.body.default_language) || currentSettings.default_language,
        date_format: cleanString(req.body.date_format) || currentSettings.date_format,
        decimal_separator:
          cleanString(req.body.decimal_separator) || currentSettings.decimal_separator,
        thousands_separator:
          cleanString(req.body.thousands_separator) || currentSettings.thousands_separator,
        session_expiration_minutes: Number(
          req.body.session_expiration_minutes ||
            currentSettings.session_expiration_minutes,
        ),
        max_failed_logins_before_lockout: Number(
          req.body.max_failed_logins_before_lockout ||
            currentSettings.max_failed_logins_before_lockout,
        ),
        password_minimum_length: Number(
          req.body.password_minimum_length || currentSettings.password_minimum_length,
        ),
      };

      if (payload.session_expiration_minutes < 5) {
        throw new ApiError(400, "L'expiration de session doit être d'au moins 5 minutes.");
      }

      if (payload.max_failed_logins_before_lockout < 1) {
        throw new ApiError(
          400,
          "Le nombre maximal d'échecs avant verrouillage doit être supérieur à zéro.",
        );
      }

      if (payload.password_minimum_length < 6) {
        throw new ApiError(400, "La longueur minimale du mot de passe doit être d'au moins 6.");
      }

      const { rows } = await client.query(
        `
          UPDATE system_settings
          SET
            application_name = $1,
            default_language = $2,
            date_format = $3,
            decimal_separator = $4,
            thousands_separator = $5,
            session_expiration_minutes = $6,
            max_failed_logins_before_lockout = $7,
            password_minimum_length = $8,
            updated_by = $9,
            updated_at = CURRENT_TIMESTAMP
          WHERE id = 1
          RETURNING *
        `,
        [
          payload.application_name,
          payload.default_language,
          payload.date_format,
          payload.decimal_separator,
          payload.thousands_separator,
          payload.session_expiration_minutes,
          payload.max_failed_logins_before_lockout,
          payload.password_minimum_length,
          req.user?.sub || null,
        ],
      );

      const updatedSettings = normalizeSystemSettings(rows[0]);

      await logAudit(client, {
        companyId: null,
        userId: req.user?.sub || null,
        action: "system_settings.update",
        entityType: "system_settings",
        entityId: 1,
        oldData: currentSettings,
        newData: updatedSettings,
        ipAddress: req.ip,
      });

      await client.query("COMMIT");

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