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

export function buildWhereFromParams(primaryKeys, params) {
  const whereParts = [];
  const values = [];
  primaryKeys.forEach((pk) => {
    if (!(pk in params)) {
      throw new ApiError(400, `Missing primary key param: ${pk}`);
    }
    whereParts.push(`\`${pk}\` = ?`);
    values.push(params[pk]);
  });
  return { where: whereParts.join(" AND "), values };
}

export function listRecords(tableName) {
  return async (req, res, next) => {
    try {
      const filters = req.query || {};
      const whereParts = [];
      const values = [];

      Object.entries(filters).forEach(([key, value]) => {
        if (value === undefined || value === null || value === "") {
          return;
        }

        // Support simple "like" search using *_like query params
        if (key.endsWith("_like")) {
          const column = key.slice(0, -5);
          whereParts.push(`\`${column}\` LIKE ?`);
          values.push(`%${value}%`);
        } else {
          whereParts.push(`\`${key}\` = ?`);
          values.push(value);
        }
      });

      let sql = `SELECT * FROM \`${tableName}\``;
      if (whereParts.length) {
        sql += ` WHERE ${whereParts.join(" AND ")}`;
      }

      const [rows] = await pool.query(sql, values);
      res.json(rows);
    } catch (err) {
      next(err);
    }
  };
}

export function getRecordByPk(tableName, primaryKeys) {
  return async (req, res, next) => {
    try {
      const { where, values } = buildWhereFromParams(primaryKeys, req.params);
      const [rows] = await pool.query(
        `SELECT * FROM \`${tableName}\` WHERE ${where} LIMIT 1`,
        values
      );
      if (!rows.length) {
        throw new ApiError(404, `${tableName} record not found`);
      }
      res.json(rows[0]);
    } catch (err) {
      next(err);
    }
  };
}

export function createRecord(tableName) {
  return async (req, res, next) => {
    try {
      const body = req.body;
      if (!body || typeof body !== "object") {
        throw new ApiError(400, "Body must be JSON object");
      }
      const columns = Object.keys(body);
      const values = Object.values(body);
      if (!columns.length) {
        throw new ApiError(400, "Body cannot be empty");
      }
      const placeholders = columns.map(() => "?").join(",");
      const sql = `INSERT INTO \`${tableName}\` (${columns
        .map((c) => `\`${c}\``)
        .join(",")}) VALUES (${placeholders})`;
      const [result] = await pool.query(sql, values);
      res.status(201).json({
        insertedId: result.insertId != null ? Number(result.insertId) : null,
        affectedRows: result.affectedRows
      });
    } catch (err) {
      next(err);
    }
  };
}

export function updateRecordByPk(tableName, primaryKeys) {
  return async (req, res, next) => {
    try {
      const body = req.body;
      if (!body || typeof body !== "object") {
        throw new ApiError(400, "Body must be JSON object");
      }
      const columns = Object.keys(body);
      const values = Object.values(body);
      if (!columns.length) {
        throw new ApiError(400, "Body cannot be empty");
      }
      const { where, values: whereValues } = buildWhereFromParams(
        primaryKeys,
        req.params
      );
      const setClause = columns.map((c) => `\`${c}\` = ?`).join(", ");
      const sql = `UPDATE \`${tableName}\` SET ${setClause} WHERE ${where}`;
      const [result] = await pool.query(sql, [...values, ...whereValues]);
      res.json({ affectedRows: result.affectedRows });
    } catch (err) {
      next(err);
    }
  };
}

export function deleteRecordByPk(tableName, primaryKeys) {
  return async (req, res, next) => {
    try {
      const { where, values } = buildWhereFromParams(primaryKeys, req.params);
      const sql = `DELETE FROM \`${tableName}\` WHERE ${where}`;
      const [result] = await pool.query(sql, values);
      res.json({ affectedRows: result.affectedRows });
    } catch (err) {
      next(err);
    }
  };
}
