const express = require('express');
const db = require('../db/models');
const wrapAsync = require('../helpers').wrapAsync;
const { validateReadOnlySql } = require('../utils/sqlValidator');

const router = express.Router();
const MAX_SQL_LENGTH = 5000;
const MAX_SQL_ROWS = 1000;
const SQL_TIMEOUT_MS = 5000;

/**
 * @swagger
 * /api/sql:
 *  post:
 *    security:
 *      - bearerAuth: []
 *    summary: Execute a SELECT-only SQL query
 *    description: Executes a read-only SQL query and returns rows.
 *    requestBody:
 *      required: true
 *      content:
 *        application/json:
 *          schema:
 *            type: object
 *            properties:
 *              sql:
 *                type: string
 *            required:
 *              - sql
 *    responses:
 *      200:
 *        description: Query result
 *      400:
 *        description: Invalid SQL
 *      401:
 *        $ref: "#/components/responses/UnauthorizedError"
 *      500:
 *        description: Internal server error
 */
router.post(
  '/',
  wrapAsync(async (req, res) => {
    const { currentUser } = req;
    const isAdminUser = Boolean(
      currentUser &&
      currentUser.app_role &&
      (currentUser.app_role.name === 'Administrator' ||
        currentUser.app_role.globalAccess === true),
    );

    if (!isAdminUser) {
      return res
        .status(403)
        .json({ error: 'Only administrators can execute SQL queries' });
    }

    const { sql } = req.body;
    const validation = validateReadOnlySql(sql, { maxLength: MAX_SQL_LENGTH });
    if (!validation.valid) {
      return res.status(400).json({ error: validation.error });
    }

    const normalized = validation.normalized;
    const wrappedSql = `SELECT * FROM (${normalized}) AS query_result LIMIT ${MAX_SQL_ROWS}`;

    const rows = await db.sequelize.transaction(async (transaction) => {
      await db.sequelize.query(
        `SET LOCAL statement_timeout = ${SQL_TIMEOUT_MS}`,
        { transaction },
      );
      return db.sequelize.query(wrappedSql, {
        transaction,
        type: db.Sequelize.QueryTypes.SELECT,
      });
    });

    return res.status(200).json({
      rows,
      meta: {
        maxRows: MAX_SQL_ROWS,
        statementTimeoutMs: SQL_TIMEOUT_MS,
      },
    });
  }),
);

module.exports = router;
