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

/**
 * Role / permission data access.
 */
class Rbac_m extends CI_Model
{
    public function __construct()
    {
        parent::__construct();
        $this->load->database();
    }

    public function tables_ready()
    {
        return $this->db->table_exists('app_roles')
            && $this->db->table_exists('app_modules')
            && $this->db->table_exists('app_role_permissions');
    }

    /* -------------------- Roles -------------------- */

    public function get_roles($active_only = false)
    {
        if ($active_only) {
            $this->db->where('status', 1);
        }
        return $this->db->order_by('is_superadmin', 'DESC')
            ->order_by('name', 'ASC')
            ->get('app_roles')
            ->result();
    }

    public function get_role($id)
    {
        return $this->db->where('id', (int) $id)->get('app_roles')->row();
    }

    public function get_role_by_slug($slug)
    {
        return $this->db->where('slug', $slug)->get('app_roles')->row();
    }

    public function create_role($data)
    {
        $this->db->insert('app_roles', $data);
        return $this->db->insert_id();
    }

    public function update_role($id, $data)
    {
        return $this->db->where('id', (int) $id)->update('app_roles', $data);
    }

    public function delete_role($id)
    {
        $id = (int) $id;
        $role = $this->get_role($id);
        if (!$role || !empty($role->is_superadmin)) {
            return false;
        }
        $this->db->where('role_id', $id)->delete('app_role_permissions');
        return $this->db->where('id', $id)->delete('app_roles');
    }

    public function count_users_in_role($role_id)
    {
        if (!$this->db->field_exists('role_id', 'user')) {
            return 0;
        }
        return (int) $this->db->where('role_id', (int) $role_id)->count_all_results('user');
    }

    /* -------------------- Modules -------------------- */

    public function get_modules($grouped = false)
    {
        $rows = $this->db->where('status', 1)
            ->order_by('sort_order', 'ASC')
            ->order_by('module_name', 'ASC')
            ->get('app_modules')
            ->result();

        if (!$grouped) {
            return $rows;
        }

        $out = array();
        foreach ($rows as $row) {
            $out[$row->module_group][] = $row;
        }
        return $out;
    }

    public function get_module($module_key)
    {
        return $this->db->where('module_key', $module_key)->get('app_modules')->row();
    }

    /**
     * Insert or update a module row (for new reports without full re-install).
     */
    public function upsert_module($module_key, $module_name, $module_group, $route, $sort_order = 100)
    {
        if (!$this->db->table_exists('app_modules')) {
            return false;
        }
        $row = array(
            'module_key' => $module_key,
            'module_name' => $module_name,
            'module_group' => $module_group,
            'route' => $route,
            'sort_order' => (int) $sort_order,
            'status' => 1,
        );
        $exists = $this->get_module($module_key);
        if ($exists) {
            return $this->db->where('module_key', $module_key)->update('app_modules', $row);
        }
        return $this->db->insert('app_modules', $row);
    }

    /* -------------------- Permissions -------------------- */

    public function get_role_permissions_map($role_id)
    {
        $rows = $this->db->where('role_id', (int) $role_id)
            ->get('app_role_permissions')
            ->result();
        $map = array();
        foreach ($rows as $row) {
            $map[$row->module_key] = array(
                'can_view' => (int) $row->can_view,
                'can_export' => (int) $row->can_export,
            );
        }
        return $map;
    }

    public function save_role_permissions($role_id, $permissions)
    {
        $role_id = (int) $role_id;
        $this->db->where('role_id', $role_id)->delete('app_role_permissions');

        if (!is_array($permissions)) {
            return true;
        }

        $batch = array();
        foreach ($permissions as $module_key => $flags) {
            $module_key = preg_replace('/[^a-z0-9_]/', '', strtolower((string) $module_key));
            if ($module_key === '') {
                continue;
            }
            $can_view = !empty($flags['can_view']) ? 1 : 0;
            $can_export = !empty($flags['can_export']) ? 1 : 0;
            if (!$can_view && !$can_export) {
                continue;
            }
            // Export implies view
            if ($can_export && !$can_view) {
                $can_view = 1;
            }
            $batch[] = array(
                'role_id' => $role_id,
                'module_key' => $module_key,
                'can_view' => $can_view,
                'can_export' => $can_export,
            );
        }

        if ($batch) {
            $this->db->insert_batch('app_role_permissions', $batch);
        }
        return true;
    }

    public function grant_all_permissions($role_id, $with_export = true)
    {
        $modules = $this->get_modules(false);
        $perms = array();
        foreach ($modules as $m) {
            $perms[$m->module_key] = array(
                'can_view' => 1,
                'can_export' => $with_export ? 1 : 0,
            );
        }
        return $this->save_role_permissions($role_id, $perms);
    }

    /**
     * Session-ready permission map for a user.
     */
    public function permissions_for_user($user)
    {
        if (!$user) {
            return array();
        }

        $role_id = isset($user->role_id) ? (int) $user->role_id : 0;
        $role = $role_id ? $this->get_role($role_id) : null;

        if ($role && !empty($role->is_superadmin)) {
            return array('_superadmin' => true);
        }

        // Legacy Admin without role_id
        if (!$role && isset($user->usertype) && $user->usertype === 'Admin') {
            return array('_superadmin' => true);
        }

        if (!$role_id) {
            return array();
        }

        return $this->get_role_permissions_map($role_id);
    }

    public function is_superadmin_user($user)
    {
        if (!$user) {
            return false;
        }
        $role_id = isset($user->role_id) ? (int) $user->role_id : 0;
        if ($role_id) {
            $role = $this->get_role($role_id);
            return $role && !empty($role->is_superadmin);
        }
        return isset($user->usertype) && $user->usertype === 'Admin';
    }
}
