const crypto =
  require("crypto");

const jwt =
  require("jsonwebtoken");

const {
  pool
} = require("../config/db");

const hashSessionToken = (
  sessionToken
) => {
  return crypto
    .createHash("sha256")
    .update(sessionToken)
    .digest("hex");
};

const sendUnauthorized = (
  response,
  message =
    "Your administrator session is invalid or has expired."
) => {
  return response.status(401).json({
    success: false,
    message
  });
};

const verifyAdminToken = async (
  request,
  response,
  next
) => {
  try {
    const authorizationHeader =
      request.get(
        "authorization"
      );

    if (
      !authorizationHeader ||
      !authorizationHeader.startsWith(
        "Bearer "
      )
    ) {
      return sendUnauthorized(
        response,
        "Administrator authentication is required."
      );
    }

    const accessToken =
      authorizationHeader
        .slice(7)
        .trim();

    if (!accessToken) {
      return sendUnauthorized(
        response
      );
    }

    const jwtSecret =
      process.env
        .ADMIN_JWT_SECRET;

    if (!jwtSecret) {
      console.error(
        "ADMIN_JWT_SECRET is missing."
      );

      return response.status(500).json({
        success: false,
        message:
          "Administrator authentication is not configured."
      });
    }

    const tokenPayload =
      jwt.verify(
        accessToken,
        jwtSecret,
        {
          algorithms: [
            "HS256"
          ],

          issuer:
            "cagd-srms",

          audience:
            "cagd-admin"
        }
      );

    if (
      tokenPayload.type !==
        "admin_access" ||
      !tokenPayload.sub ||
      !tokenPayload.sid
    ) {
      return sendUnauthorized(
        response
      );
    }

    const sessionTokenHash =
      hashSessionToken(
        tokenPayload.sid
      );

    const [sessionRows] =
      await pool.query(
        `
          SELECT
            adm_session.id
              AS session_id,

            adm_session.admin_user_id,
            adm_session.expires_at,

            adm_user.full_name,
            adm_user.username,
            adm_user.email,
            adm_user.role,
            adm_user.status,
            adm_user.locked_until,
            adm_user.last_login_at,
            adm_user.password_changed_at

          FROM admin_sessions
            AS adm_session

          INNER JOIN admin_users
            AS adm_user
            ON adm_user.id =
              adm_session.admin_user_id

          WHERE
            adm_session.session_token_hash = ?

            AND adm_session.revoked_at
              IS NULL

            AND adm_session.expires_at
              > NOW()

          LIMIT 1
        `,
        [
          sessionTokenHash
        ]
      );

    const session =
      sessionRows[0];

    if (!session) {
      return sendUnauthorized(
        response
      );
    }

    if (
      String(
        session.admin_user_id
      ) !==
      String(
        tokenPayload.sub
      )
    ) {
      return sendUnauthorized(
        response
      );
    }

    if (
      session.status !==
      "active"
    ) {
      return response.status(403).json({
        success: false,
        message:
          "This administrator account is not active."
      });
    }

    await pool.query(
      `
        UPDATE admin_sessions
        SET last_used_at = NOW()
        WHERE id = ?
      `,
      [
        session.session_id
      ]
    );

    request.admin = {
      id:
        session.admin_user_id,

      full_name:
        session.full_name,

      username:
        session.username,

      email:
        session.email,

      role:
        session.role,

      status:
        session.status,

      last_login_at:
        session.last_login_at,

      password_changed_at:
        session.password_changed_at
    };

    request.adminSession = {
      id:
        session.session_id,

      expires_at:
        session.expires_at
    };

    request.adminAccessToken =
      accessToken;

    return next();
  } catch (error) {
    if (
      error.name ===
        "TokenExpiredError" ||
      error.name ===
        "JsonWebTokenError" ||
      error.name ===
        "NotBeforeError"
    ) {
      return sendUnauthorized(
        response
      );
    }

    console.error(
      "Admin authentication error:",
      error
    );

    return response.status(500).json({
      success: false,
      message:
        "Unable to verify the administrator session."
    });
  }
};

module.exports = {
  verifyAdminToken
};