import { pool } from "../config/db.js";
import { ApiError } from "../utils/ApiError.js";
import { getJwtUserId } from "../middlewares/authMiddleware.js";
import { snapshotSectionLog } from "../utils/auditLogs.js";
import { archivePtwSectionParent } from "../utils/ptwVersioning.js";

const SECTION_COLUMNS = [
  "section_parent_id",
  "title",
  "created_by",
  "created_date"
];

function toPositiveInt(value, fieldName) {
  const n = Number(value);
  if (!Number.isInteger(n) || n <= 0) {
    throw new ApiError(400, `${fieldName} must be a positive integer`);
  }
  return n;
}

function actorId(req) {
  const raw = getJwtUserId(req.user);
  const n = raw != null ? Number(raw) : NaN;
  return Number.isInteger(n) && n > 0 ? n : null;
}

function pickColumns(body, allowed) {
  const out = {};
  for (const col of allowed) {
    if (Object.prototype.hasOwnProperty.call(body, col) && body[col] !== undefined) {
      out[col] = body[col];
    }
  }
  return out;
}

export async function createSection(req, res, next) {
  const conn = await pool.getConnection();
  try {
    const write = pickColumns(req.body || {}, SECTION_COLUMNS);
    const columns = Object.keys(write);
    if (!columns.length) throw new ApiError(400, "Body cannot be empty");

    await conn.beginTransaction();

    const placeholders = columns.map(() => "?").join(",");
    const [result] = await conn.query(
      `INSERT INTO ptw_section_details (${columns.map((c) => `\`${c}\``).join(",")}) VALUES (${placeholders})`,
      columns.map((c) => write[c])
    );
    const sectionId = Number(result.insertId);

    if (write.section_parent_id != null && write.section_parent_id !== "") {
      await archivePtwSectionParent(conn, write.section_parent_id);
    }

    await conn.commit();
    res.status(201).json({ insertedId: sectionId, affectedRows: result.affectedRows });
  } catch (err) {
    await conn.rollback().catch(() => {});
    next(err);
  } finally {
    conn.release();
  }
}

export async function updateSection(req, res, next) {
  const conn = await pool.getConnection();
  try {
    const sectionId = toPositiveInt(req.params.section_id, "section_id");
    const write = pickColumns(req.body || {}, SECTION_COLUMNS);
    const columns = Object.keys(write);
    if (!columns.length) throw new ApiError(400, "Body cannot be empty");

    await conn.beginTransaction();
    await snapshotSectionLog(conn, sectionId, actorId(req), "UPDATE");

    const setClause = columns.map((c) => `\`${c}\` = ?`).join(", ");
    const [result] = await conn.query(
      `UPDATE ptw_section_details SET ${setClause} WHERE section_id = ?`,
      [...columns.map((c) => write[c]), sectionId]
    );

    await conn.commit();
    res.json({ affectedRows: result.affectedRows });
  } catch (err) {
    await conn.rollback().catch(() => {});
    next(err);
  } finally {
    conn.release();
  }
}

export async function deleteSection(req, res, next) {
  const conn = await pool.getConnection();
  try {
    const sectionId = toPositiveInt(req.params.section_id, "section_id");

    await conn.beginTransaction();
    await snapshotSectionLog(conn, sectionId, actorId(req), "DELETE");

    // Clear dependent mappings first to satisfy FK constraints.
    await conn.query("DELETE FROM ptw_section_question_map WHERE section_id = ?", [sectionId]);
    await conn.query("DELETE FROM ptw_form_section_map WHERE section_id = ?", [sectionId]);
    await conn.query(
      "DELETE FROM ptw_alternative_sections WHERE skipable_section_id = ? OR other_section_id = ?",
      [sectionId, sectionId]
    );
    await conn.query("DELETE FROM ptw_archive_section WHERE section_id = ?", [sectionId]);

    const [result] = await conn.query(
      "DELETE FROM ptw_section_details WHERE section_id = ?",
      [sectionId]
    );

    await conn.commit();
    res.json({ affectedRows: result.affectedRows });
  } catch (err) {
    await conn.rollback().catch(() => {});
    next(err);
  } finally {
    conn.release();
  }
}
