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

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

/**
 * Creates a new `orac_form_details` row (new version) with `form_parent_id` = source form,
 * copies `orac_form_section_map` and `orac_location_forms_details` so the new form matches the parent.
 * Section–question links are global to each section (unchanged).
 */
export async function forkOracFormVersion(req, res, next) {
  const conn = await pool.getConnection();
  try {
    const formId = toPositiveInteger(req.params.form_id, "form_id");

    const [rows] = await conn.query(
      "SELECT `form_id`, `title`, `description`, `created_by` FROM `orac_form_details` WHERE `form_id` = ? LIMIT 1",
      [formId]
    );
    if (!rows.length) {
      throw new ApiError(404, "Form not found");
    }
    const parent = rows[0];

    const bodyCreatedBy = req.body?.created_by;
    const jwtUserId = req.user?.user_id != null ? Number(req.user.user_id) : null;
    const createdBy =
      bodyCreatedBy != null && bodyCreatedBy !== ""
        ? Number(bodyCreatedBy)
        : Number.isInteger(jwtUserId) && jwtUserId > 0
          ? jwtUserId
          : parent.created_by != null
            ? Number(parent.created_by)
            : null;

    await conn.beginTransaction();

    const [ins] = await conn.query(
      `INSERT INTO \`orac_form_details\`
         (\`form_parent_id\`, \`title\`, \`description\`, \`created_by\`, \`created_date\`)
       VALUES (?, ?, ?, ?, NOW())`,
      [formId, parent.title, parent.description, Number.isFinite(createdBy) ? createdBy : null]
    );

    const newId = ins.insertId;
    if (!Number.isInteger(newId) || newId <= 0) {
      throw new ApiError(500, "Could not allocate new form_id");
    }

    await conn.query(
      `INSERT INTO \`orac_form_section_map\` (\`form_id\`, \`section_id\`)
       SELECT ?, \`section_id\` FROM \`orac_form_section_map\` WHERE \`form_id\` = ?`,
      [newId, formId]
    );

    await conn.query(
      `INSERT INTO \`orac_location_forms_details\` (\`form_id\`, \`location_id\`)
       SELECT ?, \`location_id\` FROM \`orac_location_forms_details\` WHERE \`form_id\` = ?`,
      [newId, formId]
    );

    await archiveOracFormParent(conn, formId);

    await conn.commit();

    return res.status(201).json({
      insertedId: newId,
      form_parent_id: formId,
      message: "New form version created; previous form is archived in orac_archive_form."
    });
  } catch (err) {
    await conn.rollback().catch(() => {});
    return next(err);
  } finally {
    conn.release();
  }
}
