<?php
defined('BASEPATH') OR exit('No direct script access allowed');

/**
 * Auth — admin authentication & role-based access control.
 * --------------------------------------------------------------------------
 * The user model is lazy-loaded (not in the constructor) to avoid an HMVC
 * module-loading recursion when this library is loaded inside an admin
 * controller during bootstrap.
 * --------------------------------------------------------------------------
 */
#[\AllowDynamicProperties]
class Auth {

	/** @var object CI super-object */
	protected $CI;

	/** Role hierarchy — higher number = more privilege. */
	protected $hierarchy = array(
		'editor'      => 1,
		'super_admin' => 2,
	);

	public function __construct()
	{
		$this->CI =& get_instance();
		$this->CI->load->library('session');
	}

	/** Lazy-load the user model on first use. */
	private function users()
	{
		if ( ! isset($this->CI->user_model))
		{
			$this->CI->load->model('user_model');
		}
		return $this->CI->user_model;
	}

	/* --------------------------------------------------------------------
	 * AUTHENTICATION
	 * ----------------------------------------------------------------- */

	/**
	 * Attempt to log a user in with email + password.
	 * Returns TRUE on success, or a string error message on failure.
	 */
	public function attempt($email, $password)
	{
		$user = $this->users()->by_email($email);

		if ( ! $user)
		{
			return 'No active account found for that email.';
		}

		if ( ! password_verify($password, $user['password']))
		{
			return 'The password you entered is incorrect.';
		}

		// Re-hash if PHP's default cost has changed.
		if (password_needs_rehash($user['password'], PASSWORD_BCRYPT))
		{
			$this->users()->update($user['id'], array(
				'password' => password_hash($password, PASSWORD_BCRYPT),
			));
		}

		$this->users()->mark_login($user['id']);

		$this->CI->session->set_userdata(array(
			'admin_logged_in' => TRUE,
			'admin_id'        => $user['id'],
			'admin_name'      => $user['name'],
			'admin_email'     => $user['email'],
			'admin_role'      => $user['role'],
			'admin_avatar'    => $user['avatar'],
		));

		return TRUE;
	}

	/** Log the current user out. */
	public function logout()
	{
		$this->CI->session->unset_userdata(array(
			'admin_logged_in', 'admin_id', 'admin_name',
			'admin_email', 'admin_role', 'admin_avatar',
		));
		$this->CI->session->sess_destroy();
	}

	/** Whether a user is currently logged in. */
	public function logged_in()
	{
		return (bool) $this->CI->session->userdata('admin_logged_in');
	}

	/** Return the current user as an array (from session). */
	public function user()
	{
		if ( ! $this->logged_in()) return array();
		return array(
			'id'     => $this->CI->session->userdata('admin_id'),
			'name'   => $this->CI->session->userdata('admin_name'),
			'email'  => $this->CI->session->userdata('admin_email'),
			'role'   => $this->CI->session->userdata('admin_role'),
			'avatar' => $this->CI->session->userdata('admin_avatar'),
		);
	}

	/** Current user's ID. */
	public function id()
	{
		return $this->CI->session->userdata('admin_id');
	}

	/* --------------------------------------------------------------------
	 * AUTHORISATION (RBAC)
	 * ----------------------------------------------------------------- */

	/**
	 * Check whether the current user meets a minimum role.
	 * e.g. has_role('super_admin') is TRUE only for super admins;
	 *      has_role('editor') is TRUE for editors AND super admins.
	 */
	public function has_role($minimum)
	{
		$role = $this->CI->session->userdata('admin_role');
		if ( ! $role || ! isset($this->hierarchy[$role])) return FALSE;
		$need = isset($this->hierarchy[$minimum]) ? $this->hierarchy[$minimum] : 99;
		return $this->hierarchy[$role] >= $need;
	}

	/** Convenience: is the current user a super admin? */
	public function is_super()
	{
		return $this->CI->session->userdata('admin_role') === 'super_admin';
	}
}
