<?php

namespace App\Controllers\View;

use CodeIgniter\Events\Events;
use App\Controllers\BaseController;
use App\Models\UserModel;  // Assuming you have a UserModel
use App\Models\PasswordResetModel; // Model for the password_resets table
use CodeIgniter\I18n\Time;
use App\Models\RoleModel;
use App\Models\UserRoleModel;
use App\Models\PasswordResetRequestModel;
use App\Models\RolePermissionModel;
use App\Models\IpAttemptModel;
use CodeIgniter\Controller;
use App\Controllers\View\EmailController;
use App\Models\LoginActivityModel; // Make sure this import is present
require_once APPPATH . 'Helpers/pbkdf2_helper.php';



class UserController extends BaseController
{
    private const ACTIVATION_TTL_HOURS = 48;
    protected $userModel;
    protected $roleModel;
    protected $userRoleModel;
    protected $db;
    protected $passwordResetModel;
    protected $loginActivityModel;
    protected $resetRequestModel;

    public function __construct()
    {
        // Load the database service
        $this->db = \Config\Database::connect();
        // Check if the database connection is established
        if (!$this->db->connect()) {
            log_message('error', 'Database connection failed.');
            throw new \Exception('Database connection failed.');
        } else {
            log_message('info', 'Database connection successful.');
        }
        helper('auth');
        $this->userModel = new UserModel();
        $this->roleModel = new RoleModel();
        $this->userRoleModel = new UserRoleModel();
        $this->passwordResetModel = new PasswordResetModel();
        $this->loginActivityModel = new LoginActivityModel();
        $this->resetRequestModel = new PasswordResetRequestModel();
    }

    private function denyAccess(string $message)
    {
        if ($this->request->isAJAX() || $this->request->getHeaderLine('Accept') === 'application/json') {
            return service('response')
                ->setStatusCode(403)
                ->setJSON(['status' => 'error', 'message' => $message]);
        }

        session()->setFlashdata('error', $message);
        return redirect()->to('/access_denied');
    }

    private function requirePermission(string $permission)
    {
        if (!session()->get('is_logged_in')) {
            return redirect()->to('/login');
        }

        $userId = (int) session()->get('user_id');
        if ($userId <= 0 || !has_permission($userId, $permission)) {
            return $this->denyAccess("You don't have permission to use this feature.");
        }

        return null;
    }

    private function hashToken(string $token): string
    {
        return hash('sha256', $token);
    }

    private function redirectWithoutLegacyTermFilters(string $route): ?\CodeIgniter\HTTP\RedirectResponse
    {
        $legacyTermKeys = ['school_year', 'schoolYear', 'year', 'semester'];
        $query = $this->request->getGet();
        $hasLegacyTermFilter = false;

        foreach ($legacyTermKeys as $key) {
            if (array_key_exists($key, $query)) {
                unset($query[$key]);
                $hasLegacyTermFilter = true;
            }
        }

        if (!$hasLegacyTermFilter) {
            return null;
        }

        $target = site_url($route) . (!empty($query) ? '?' . http_build_query($query) : '');
        return redirect()->to($target);
    }

    // Method to show the home page
    public function home()
    {
        return view('/index');
    }

    // Method to show the about page
    public function about()
    {
        return view('/about');
    }

    // Method to show the classes page
    public function classes()
    {
        return view('/classes');
    }

    // Method to show the contact page
    public function contact()
    {
        return view('/contact');
    }

    public function userList()
    {
        if ($resp = $this->requirePermission('read_user')) {
            return $resp;
        }

        helper('url');

        if ($redirect = $this->redirectWithoutLegacyTermFilters('user/user_list')) {
            return $redirect;
        }

        return view('user/user_list', [
            'userListEndpoint' => site_url('api/users'),
        ]);
    }

    // Method to show the list of users   
    public function index()
    {
        if ($resp = $this->requirePermission('read_user')) {
            return $resp;
        }

        // Fetch users along with their assigned roles
        $builder = $this->db->table('users');
        $builder->select('users.id, users.firstname, users.lastname, users.email, user_roles.role_id, roles.name as role, users.status, users.updated_at');
        $builder->join('user_roles', 'users.id = user_roles.user_id', 'left');
        $builder->join('roles', 'user_roles.role_id = roles.id', 'left');

        $sort = $this->request->getGet('sort');
        $order = $this->request->getGet('order') === 'desc' ? 'desc' : 'asc';

        // Define allowed fields for sorting
        $allowedFields = ['id', 'firstname', 'lastname', 'email', 'role'];

        if (in_array($sort, $allowedFields)) {
            $sort_column = $sort === 'role' ? 'roles.name' : 'users.' . $sort;
            $builder->orderBy($sort_column, $order);
        } else {
            $builder->orderBy('users.id', 'asc');
        }

        $query = $builder->get();
        $users = $query->getResultArray();

        // Fetch available roles
        $roleBuilder = $this->db->table('roles');
        $roleQuery = $roleBuilder->get();
        $roles = $roleQuery->getResultArray();

        return view('user/user_list', [
            'users' => $users,
            'roles' => $roles,
            'sort' => $sort,
            'order' => $order,
        ]);
    }

    public function userListData()
    {
        if ($resp = $this->requirePermission('read_user')) {
            return $resp;
        }

        return $this->response->setJSON([
            'users' => $this->buildUsersWithRoles(),
        ]);
    }

    private function buildUsersWithRoles(): array
    {
        // Fetch all users
        $users = $this->userModel->findAll();
        if (!is_array($users)) {
            return [];
        }

        // Aggregate guardian types (primary/secondary) by user_id
        $gmap = [];
        try {
            $rows = $this->db->table('family_guardians')
                ->select('user_id, MAX(is_primary) AS max_primary, COUNT(*) AS cnt', false)
                ->groupBy('user_id')
                ->get()->getResultArray();
            foreach ($rows as $r) {
                $uid = (int)($r['user_id'] ?? 0);
                if ($uid <= 0) continue;
                $maxp = (int)($r['max_primary'] ?? 0);
                $cnt  = (int)($r['cnt'] ?? 0);
                if ($cnt > 0) {
                    $gmap[$uid] = $maxp > 0 ? 'Primary' : 'Secondary';
                }
            }
        } catch (\Throwable $e) {
            // ignore if table missing; leave map empty
        }

        // Aggregate "second parent presence" from legacy parents table
        $secondByUserId = [];
        $secondByEmail  = [];
        try {
            $parentFields = $this->db->getFieldNames('parents');
            $hasSecondUid   = in_array('secondparent_user_id', $parentFields, true);
            $hasSecondEmail = in_array('secondparent_email', $parentFields, true);

            if ($hasSecondUid) {
                // Map: user_id present in parents.secondparent_user_id
                $uidRows = $this->db->table('parents')
                    ->select('secondparent_user_id AS uid, COUNT(*) AS cnt', false)
                    ->where('secondparent_user_id !=', 0)
                    ->groupBy('secondparent_user_id')
                    ->get()->getResultArray();
                foreach ($uidRows as $r) {
                    $u = (int)($r['uid'] ?? 0);
                    if ($u > 0) {
                        $secondByUserId[$u] = true;
                    }
                }
            }

            if ($hasSecondEmail) {
                // Map: email present in parents.secondparent_email
                $emailRows = $this->db->table('parents')
                    ->select('LOWER(TRIM(secondparent_email)) AS em, COUNT(*) AS cnt', false)
                    ->where('secondparent_email !=', '')
                    ->groupBy('secondparent_email')
                    ->get()->getResultArray();
                foreach ($emailRows as $r) {
                    $em = trim(strtolower((string)($r['em'] ?? '')));
                    if ($em !== '') {
                        $secondByEmail[$em] = true;
                    }
                }
            }
        } catch (\Throwable $e) {
            // ignore if legacy table or fields are missing
        }

        // Prepare an array to store user data along with their roles
        $usersWithRoles = [];

        // Loop through each user and get their roles
        foreach ($users as $user) {
            if (!is_array($user)) {
                continue;
            }

            // Get the user's roles from the user_roles table
            $userRoles = $this->userRoleModel->where('user_id', $user['id'])->findAll() ?? [];

            // Initialize arrays to hold role names/ids for this user
            $roleNames = [];
            $roleIds   = [];

            // Fetch role names from the roles table
            foreach ($userRoles as $userRole) {
                if (!is_array($userRole) || empty($userRole['role_id'])) {
                    continue;
                }
                $role = $this->roleModel->find($userRole['role_id']);
                if ($role) {
                    $roleIds[]   = (int) $role['id'];
                    $roleNames[] = $role['name'];
                }
            }

            // Parent type if user is a guardian in any family
            $parentType = $gmap[(int)($user['id'] ?? 0)] ?? '';

            // Second-from-parents flag: by secondparent_user_id or secondparent_email
            $isSecond = false;
            $uid = (int)($user['id'] ?? 0);
            if ($uid > 0 && !empty($secondByUserId[$uid])) {
                $isSecond = true;
            } else {
                $em = trim(strtolower((string)($user['email'] ?? '')));
                if ($em !== '' && !empty($secondByEmail[$em])) $isSecond = true;
            }

            // Add the user data along with role names to the result array
            $usersWithRoles[] = [
                'user'         => $user,
                'roles'        => $roleNames,
                'role_ids'     => $roleIds,
                'parent_type'  => $parentType, // 'Primary', 'Secondary', or ''
                'second_from_parents' => $isSecond ? 'Yes' : '',
            ];
        }

        return $usersWithRoles;
    }

    // Method to store a new user
    public function store()
    {
        if ($resp = $this->requirePermission('edit_user')) {
            return $resp;
        }

        // Validate input data
        $validation = \Config\Services::validation();
        $validation->setRules([
            'username' => 'required',
            'password' => 'required|min_length[6]',
            'lastname' => 'required',
            'firstname' => 'required',
            'cellphone' => 'required',
            'email' => 'required|valid_email',
            'address_street' => 'required',
            'city' => 'required',
            'state' => 'required',
            'zip' => 'required',
            'accept_school_policy' => 'required',
            'role_id' => 'required|integer'
        ]);

        if (!$this->validate($validation->getRules())) {
            $errors = $validation->getErrors();
            return redirect()->back()->withInput()->with('errors', $errors);
        }

        // Prepare user data for insertion
        $userData = [
            'username' => $this->request->getPost('username'),
            'password' => pbkdf2_hash($this->request->getPost('password')),
            'lastname' => ucfirst($this->request->getPost('lastname')),
            'firstname' => ucfirst($this->request->getPost('firstname')),
            'cellphone' => $this->request->getPost('cellphone'),
            'email' => strtolower($this->request->getPost('email')),
            'address_street' => $this->request->getPost('address_street'),
            'city' => ucfirst($this->request->getPost('city')),
            'state' => $this->request->getPost('state'),
            'zip' => $this->request->getPost('zip'),
            'accept_school_policy' => $this->request->getPost('accept_school_policy'),
        ];

        // Insert user data into the database
        if ($this->userModel->save($userData) === false) {
            return redirect()->back()->withInput()->with('errors', $this->userModel->errors());
        }

        // Retrieve the newly created user ID
        $userId = $this->userModel->getInsertID();

        // Assign the role to the user in the user_roles table
        $roleData = [
            'user_id' => $userId,
            'role_id' => $this->request->getPost('role_id'),
            'created_at' => utc_now(),
        ];

        if ($this->userRoleModel->save($roleData) === false) {
            return redirect()->back()->withInput()->with('errors', $this->userRoleModel->errors());
        }

        return redirect()->to('/user');
    }

    // Method to show the form for editing an existing user
    public function edit($id)
    {
        if ($resp = $this->requirePermission('edit_user')) {
            return $resp;
        }

        $data['user'] = $this->userModel->find($id);
        $data['roles'] = $this->roleModel->findAll();
        $userRoles = $this->userRoleModel->where('user_id', $id)->findAll();
        $data['assignedRoles'] = array_column($userRoles, 'role_id');

        return view('user/edit', $data);
    }


    // Method to delete an existing user
    public function delete($id)
    {
        if ($resp = $this->requirePermission('edit_user')) {
            return $resp;
        }

        $this->userModel->delete($id);

        // Delete the user's roles from the user_roles table
        $this->userRoleModel->where('user_id', $id)->delete();

        return redirect()->to('/user');
    }


    //This function is necessary to display the initial forgot password form where the user enters their email address.
    public function forgotPassword()
    {
        return view('/user/forgot_password');
    }

    //This function is crucial for processing the forgot password request, generating a reset token, storing it in the database, and sending an email with the reset link.
    public function processForgotPassword()
    {
        log_message('debug', 'Entered processForgotPassword');

        $ip = $this->request->getIPAddress();

        $recentAttempts = $this->resetRequestModel
            ->where('ip_address', $ip)
            ->where('requested_at >=', Time::now()->subHours(24)->toDateTimeString())
            ->countAllResults();

        if ($recentAttempts >= 3) {
            log_message('warning', "IP {$ip} blocked due to too many reset attempts.");
            session()->setFlashdata('show_block_modal', true);
            return redirect()->back();
        }

        // Log this attempt
        $this->resetRequestModel->insert([
            'ip_address'   => $ip,
            'requested_at' => Time::now(),
        ]);

        $email = strtolower($this->request->getPost('email'));
        $user  = $this->userModel->where('email', $email)->first();

        // --- Handle unknown or unverified email ---
        if (!$user || (int) $user['is_verified'] === 0) {
            session()->setFlashdata('success', 'If this email is registered, you will receive a reset link.');
            log_message('info', "Password reset requested for {$email} (user missing or unverified).");
            return redirect()->back();
        }

        // --- Verified user: continue with reset ---
        $token      = bin2hex(random_bytes(48));
        $tokenHash  = $this->hashToken($token);
        $expires_at = Time::now()->addHours(1);

        $this->passwordResetModel->insert([
            'email'      => $email,
            'token'      => $tokenHash,
            'created_at' => Time::now(),
            'expires_at' => $expires_at,
        ]);

        $this->sendResetEmail($email, $token);

        session()->setFlashdata('success', 'A password reset link has been sent to your email.');
        log_message('info', "Password reset email sent to {$email}");

        return redirect()->back();
    }


    public function blocked()
    {
        session()->setFlashdata('show_block_modal', true);
        return redirect()->back(); // Show modal on the previous page
    }

    //This function is needed to display a confirmation page after the reset email has been sent, informing the user to check their email.
    public function passwordResetConfirmation()
    {
        $email = session()->getFlashdata('reset_email');

        return view('user/password_reset_confirmation', ['email' => $email]);
    }

    //This is a private helper function that handles sending the reset email. It’s separated out to keep the processForgotPassword function clean and focused.
    public function sendResetEmail($email, $token)
    {
        $resetLink = site_url('/reset_password?token=' . $token);

        // Render email template with data
        $message = view('emails/reset_password', ['resetLink' => $resetLink]);

        $emailController = new EmailController();
        $subject = 'Password Reset Request';

        if ($emailController->sendEmail($email, $subject, $message)) {
            log_message('info', 'Password reset email successfully sent to ' . $email);
        } else {
            log_message('error', 'Failed to send password reset email to ' . $email);
        }
    }


    //This function is necessary to display the form where the user can enter a new password, after clicking on the reset link in their email.
    public function resetPassword()
    {
        // Retrieve the token from the query string
        $token = $this->request->getGet('token');

        if (!$token) {
            return redirect()->to('/')->with('error', 'Invalid password reset link.');
        }

        // You may want to validate the token here
        $tokenHash = $this->hashToken($token);
        $resetEntry = $this->passwordResetModel
            ->groupStart()
            ->where('token', $tokenHash)
            ->orWhere('token', $token)
            ->groupEnd()
            ->where('expires_at >=', Time::now())
            ->first();

        if (!$resetEntry) {
            return redirect()->to('/')->with('error', 'Invalid or expired reset link.');
        }

        // Load the reset password view with the token
        return view('user/reset_password', ['token' => $token]);
    }

    //This function processes the new password submission, validating the token, updating the user's password, and cleaning up the reset entry.
    public function processResetPassword()
    {
        if (strtolower($this->request->getMethod()) !== 'post') {
            return redirect()->to('/')->with('error', 'Invalid request.');
        }

        $token = $this->request->getPost('token');
        $newPassword = $this->request->getPost('password');
        $passConfirm = $this->request->getPost('pass_confirm');

        // Validate the input
        if (!$this->validate([
            'password' => [
                'label' => 'Password',
                'rules' => 'required|min_length[8]|regex_match[/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@\-=\+*#$%&!?])[A-Za-z\d@\-=\+*#$%&!?]{8,}$/]',
                'errors' => [
                    'required' => 'Password is required.',
                    'min_length' => 'Password must be at least 8 characters.',
                    'regex_match' => 'Password must contain at least one lowercase letter, one uppercase letter, one number, and one special character (@, -, =, +, *, #, $, %, &, !, ?).'
                ]
            ],
            'pass_confirm' => [
                'label' => 'Confirm Password',
                'rules' => 'required|matches[password]',
                'errors' => [
                    'required' => 'Password confirmation is required.',
                    'matches' => 'Passwords do not match.'
                ]
            ]
        ])) {
            return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
        }

        // Find the password reset entry
        $tokenHash = $this->hashToken($token);
        $resetEntry = $this->passwordResetModel
            ->groupStart()
            ->where('token', $tokenHash)
            ->orWhere('token', $token)
            ->groupEnd()
            ->where('expires_at >=', Time::now())
            ->first();

        if (!$resetEntry) {
            return redirect()->to('/')->with('error', 'Invalid or expired reset link.');
        }

        // Find the user by email
        $user = $this->userModel->where('email', $resetEntry['email'])->first();

        if (!$user) {
            return redirect()->to('/')->with('error', 'User not found.');
        }

        // 🛠 Hash the password using PBKDF2
        $hashedPassword = pbkdf2_hash($newPassword);

        // Update the password in the users table and set the account status to 'Active'
        // Reset failed login attempts, suspension status, and last failed login time
        $this->userModel->update($user['id'], [
            'failed_attempts' => 0, // Reset failed attempts
            'is_suspended'    => 0, // Unsuspend the account
            'last_failed_at'  => null, // Reset the last failed login timestamp
            'password' => $hashedPassword,
            'status' => 'Active'
        ]);

        // Delete the used token from the password reset table
        $this->passwordResetModel
            ->groupStart()
            ->where('token', $tokenHash)
            ->orWhere('token', $token)
            ->groupEnd()
            ->delete();

        // Retrieve the user's IP address from the request
        $ipAddress = $this->request->getIPAddress();

        // Delete the corresponding entry from the ip_attempts table, only if it exists
        $ipAttemptModel = new IpAttemptModel();
        $existingAttempt = $ipAttemptModel->where('ip_address', $ipAddress)->first();

        if ($existingAttempt) {
            // IP address entry exists, so delete it
            $ipAttemptModel->where('ip_address', $ipAddress)->delete();
        }

        // Redirect to a success page with a success message
        return view('user/password_set_success');
    }



    public function passwordSetSuccess()
    {
        return view('user/password_set_success');
    }

    public function confirm($token)
    {
        log_message('info', 'Processing email confirmation.');

        $tokenHash = $this->hashToken($token);
        $user = $this->userModel
            ->groupStart()
            ->where('token', $tokenHash)
            ->orWhere('token', $token)
            ->groupEnd()
            ->where('created_at >=', Time::now()->subHours(self::ACTIVATION_TTL_HOURS)->toDateTimeString())
            ->first();

        if (!$user || $user['is_verified'] == 1) {
            return redirect()->to('/invalid_token');
        }


        // Mark the user as verified and generate an account ID
        $account_id = 'ACC' . str_pad($user['id'], 8, '0', STR_PAD_LEFT); // Example: ACC00000001
        $this->userModel->update($user['id'], ['is_verified' => 1, 'token' => null, 'account_id' => $account_id]);

        log_message('info', 'User verified and account ID generated: ' . $account_id);

        // Redirect to the set password page
        return redirect()->to('/set_password/' . $user['id']);
    }

    public function setPassword($token)
    {
        //echo "Reached setPassword with token: " . esc($token);
        //echo "Token received: " . $token;
        $tokenHash = $this->hashToken($token);
        $user = $this->userModel
            ->groupStart()
            ->where('token', $tokenHash)
            ->orWhere('token', $token)
            ->groupEnd()
            ->where('created_at >=', Time::now()->subHours(self::ACTIVATION_TTL_HOURS)->toDateTimeString())
            ->first();

        if (!$user || $user['is_verified'] == 1) {
            return redirect()->to('/invalid_token');
        }

        return view('user/set_password', [
            'userId' => $user['id'],
            'token' => $token
        ]);
    }

    public function savePassword()
    {
        if (strtolower($this->request->getMethod()) !== 'post') {
            return redirect()->to('/')->with('error', 'Invalid request.');
        }

        $validation = \Config\Services::validation();
        $validation->setRules([
            'password' => [
                'label' => 'Password',
                'rules' => 'required|min_length[8]|regex_match[/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@\-=\+*#$%&!?])[A-Za-z\d@\-=\+*#$%&!?]{8,}$/]',
                'errors' => [
                    'required' => 'Password is required.',
                    'min_length' => 'Password must be at least 8 characters long.',
                    'regex_match' => 'Password must contain at least one lowercase letter, one uppercase letter, one number, and one special character (@, -, =, +, *, #, $, %, &, !, ?).'
                ]
            ],
            'password_confirm' => [
                'label' => 'Confirm Password',
                'rules' => 'required|matches[password]',
                'errors' => [
                    'required' => 'Password confirmation is required.',
                    'matches' => 'Passwords do not match.'
                ]
            ],
            'user_id' => 'required|integer',
            'token' => 'required'
        ]);

        if (!$this->validate($validation->getRules())) {
            return redirect()->back()->withInput()->with('errors', $validation->getErrors());
        }

        $userId = $this->request->getPost('user_id');
        $token  = $this->request->getPost('token');
        $password = $this->request->getPost('password');

        $tokenHash = $this->hashToken($token);
        $user = $this->userModel
            ->where('id', $userId)
            ->groupStart()
            ->where('token', $tokenHash)
            ->orWhere('token', $token)
            ->groupEnd()
            ->where('created_at >=', Time::now()->subHours(self::ACTIVATION_TTL_HOURS)->toDateTimeString())
            ->first();

        log_message('debug', "Attempting to set password for user $userId");

        if (!$user || $user['is_verified'] == 1) {
            return redirect()->to('/invalid_token');
        }

        $hashedPassword = pbkdf2_hash($password); // Or use password_hash()

        // Generate account_id only if it's not already set
        $account_id = $user['account_id'] ?? null;
        if (!$account_id) {
            $account_id = 'ACC' . str_pad($userId, 8, '0', STR_PAD_LEFT);
        }

        $this->userModel->update($userId, [
            'password'     => $hashedPassword,
            'status'       => 'Active',
            'is_verified'  => 1,
            'token'        => null,
            'account_id'   => $account_id,
        ]);

        // Optional: trigger event
        $userData = $this->userModel->getUserInfoById($userId);
        if (!is_array($userData)) {
            $userData = (array) $userData;
        }
        $userData['id'] = $userId;
        \CodeIgniter\Events\Events::trigger('user_registered', $userData);

        return redirect()->to('/user/password_set_success');
    }



    public function invalidToken()
    {
        return view('errors/invalid_token');
    }


    public function selectRole()
    {
        log_message('info', 'Processing setRole form submission.');

        if (!session()->get('is_logged_in')) {
            log_message('error', 'User is not logged in.');
            return redirect()->to('/user/login');
        }

        $roleKey = (string) $this->request->getPost('role');
        log_message('info', 'Role selected: ' . $roleKey);

        $userId = (int) session()->get('user_id');
        log_message('info', 'User ID: ' . $userId);

        if ($userId <= 0) {
            return $this->denyAccess("You don't have permission to use this feature.");
        }

        $roleRow = $this->db->table('user_roles ur')
            ->join('roles r', 'r.id = ur.role_id', 'inner')
            ->select('r.name, r.slug, r.dashboard_route')
            ->where('ur.user_id', $userId)
            ->where('r.is_active', 1)
            ->groupStart()
            ->where('LOWER(r.name)', strtolower($roleKey))
            ->orWhere('LOWER(r.slug)', strtolower($roleKey))
            ->groupEnd()
            ->get()
            ->getRowArray();

        if (empty($roleRow)) {
            log_message('error', 'Invalid or unassigned role selected: ' . $roleKey);
            return redirect()->back()->with('error', 'Invalid role selected.');
        }

        $route = $roleRow['dashboard_route'] ?? null;
        if ($route === null) {
            log_message('error', 'No dashboard route configured for role: ' . $roleKey);
            return redirect()->back()->with('error', 'Invalid role selected.');
        }

        // Persist the *exact* role name or slug—choose your convention.
        // Store the canonical name to avoid arbitrary role strings.
        $this->userModel->update($userId, ['role' => $roleRow['name']]);
        log_message('info', 'Role updated in database.');

        log_message('info', 'Redirecting to role dashboard: ' . $route);
        return redirect()->to($route);
    }


    public function welcomeBack()
    {
        if (!session()->get('is_logged_in')) {
            return redirect()->to('/user/login');
        }

        return view('user/welcome_back');
    }

    public function delete_role($roleId)
    {
        if ($resp = $this->requirePermission('edit_user')) {
            return $resp;
        }

        // Fetch the role to be deleted
        $role = $this->roleModel->find($roleId);
        if (!$role) {
            return redirect()->back()->with('error', 'Role not found.');
        }

        // Fetch the "Guest" role
        $guestRole = $this->roleModel->where('name', 'Guest')->first();
        if (!$guestRole) {
            return redirect()->back()->with('error', 'Guest role not found.');
        }

        // Update users with the deleted role to have the "Guest" role
        $this->userModel->where('role_id', $roleId)->set(['role_id' => $guestRole['id'], 'role' => 'Guest', 'status' => 'Inactive'])->update();

        // Verify that users have been updated
        $updatedUsers = $this->userModel->where('role_id', $guestRole['id'])->findAll();
        log_message('debug', 'Updated users: ' . print_r($updatedUsers, true));

        // Delete the role
        if ($this->roleModel->delete($roleId)) {
            return redirect()->to('/administrator/user_roles')->with('success', 'Role deleted successfully. Users with this role have been assigned the Guest role.');
        } else {
            return redirect()->back()->with('error', 'Failed to delete role.');
        }
    }

    public function loginActivity()
    {
        if ($resp = $this->requirePermission('view_login_activity')) {
            return $resp;
        }

        helper('url');

        if ($redirect = $this->redirectWithoutLegacyTermFilters('user/login_activity')) {
            return $redirect;
        }

        $perPage = (int) ($this->request->getGet('per_page') ?? 25);

        return view('user/login_activity', [
            'loginActivityEndpoint' => site_url('api/login-activity'),
            'defaultPerPage'        => $perPage > 0 ? $perPage : 25,
        ]);
    }

    public function loginActivityData()
    {
        if ($resp = $this->requirePermission('view_login_activity')) {
            return $resp;
        }

        $perPage = (int) ($this->request->getGet('per_page') ?? 25);
        $page    = (int) ($this->request->getGet('page') ?? 1);

        return $this->response->setJSON($this->buildLoginActivityPayload($perPage, $page));
    }

    // Method to update an existing user
    public function updateUser()
    {
        if ($resp = $this->requirePermission('edit_user')) {
            return $resp;
        }

        if (strtolower($this->request->getMethod()) !== 'post') {
            return redirect()->to(site_url('user/user_list'))->with('error', 'Invalid request.');
        }

        $id = (int) $this->request->getPost('id');
        if (!$id) {
            return redirect()->to(site_url('user/user_list'))->with('error', 'User ID is missing.');
        }

        $user = $this->userModel->find($id);
        if (!$user) {
            return redirect()->to(site_url('user/user_list'))->with('error', 'User not found.');
        }

        // Helpers
        $toBool = fn($k) => $this->request->getPost($k) ? 1 : 0;
        $toDT   = function ($key) {
            $v = trim((string)$this->request->getPost($key));
            if ($v === '') return null;
            // Expecting HTML datetime-local "YYYY-MM-DDTHH:MM"
            $ts = strtotime($v);
            return $ts ? date('Y-m-d H:i:s', $ts) : null;
        };

        $data = [
            'id'                   => $id,
            'account_id'           => trim((string)$this->request->getPost('account_id')),
            'lastname'             => trim((string)$this->request->getPost('lastname')),
            'firstname'            => trim((string)$this->request->getPost('firstname')),
            'gender'               => trim((string)$this->request->getPost('gender')),
            'cellphone'            => trim((string)$this->request->getPost('cellphone')),
            'email'                => trim((string)$this->request->getPost('email')),
            'address_street'       => trim((string)$this->request->getPost('address_street')),
            'apt'                  => trim((string)$this->request->getPost('apt')),
            'city'                 => trim((string)$this->request->getPost('city')),
            'state'                => trim((string)$this->request->getPost('state')),
            'zip'                  => trim((string)$this->request->getPost('zip')),
            'accept_school_policy' => $toBool('accept_school_policy'),
            'user_type'            => trim((string)$this->request->getPost('user_type')),
            'rfid_tag'             => trim((string)$this->request->getPost('rfid_tag')),
            'school_id'            => trim((string)$this->request->getPost('school_id')),
            'failed_attempts'      => (string)$this->request->getPost('failed_attempts') === '' ? null : (int)$this->request->getPost('failed_attempts'),
            'last_failed_at'       => $toDT('last_failed_at'),
            'semester'             => trim((string)$this->request->getPost('semester')),
            'school_year'          => trim((string)$this->request->getPost('school_year')),
            'status'               => trim((string)$this->request->getPost('status')),
            'is_suspended'         => $toBool('is_suspended'),
            'is_verified'          => $toBool('is_verified'),
        ];

        // Validation
        $rules = [
            'firstname' => 'required|min_length[2]|max_length[100]',
            'lastname'  => 'required|min_length[2]|max_length[100]',
            'email'     => "required|valid_email|is_unique[users.email,id,{$id}]",
            'state'     => 'permit_empty|max_length[2]',
            'zip'       => 'permit_empty|max_length[20]',
            'cellphone' => 'permit_empty|max_length[50]',
            'failed_attempts' => 'permit_empty|integer',
            'gender'    => 'permit_empty|in_list[male,female,MALE,FEMALE]', // adjust as needed
        ];

        if (!$this->validate($rules)) {
            return redirect()->back()
                ->with('error', implode(' ', $this->validator->getErrors()))
                ->withInput();
        }

        if (!$this->userModel->save($data)) {
            return redirect()->back()->with('error', 'Failed to update user.')->withInput();
        }

        return redirect()->to(site_url('user/user_list'))->with('success', 'User updated successfully.');
    }

    private function buildLoginActivityPayload(int $perPage, int $page): array
    {
        $perPage = max(1, min($perPage, 200));
        $page    = max(1, $page);

        $schoolYear = (string) ((new \App\Models\ConfigurationModel())->getConfig('school_year') ?? '');
        $activityModel = $this->loginActivityModel;
        if ($schoolYear !== '' && db_connect()->fieldExists('school_year', 'login_activity')) {
            $activityModel->where('school_year', $schoolYear);
        }

        $totalActivities = (int) $activityModel->countAllResults(false);
        $activities = $activityModel
            ->orderBy('login_time', 'DESC')
            ->paginate($perPage, 'loginActivity', $page) ?? [];

        $pager = $activityModel->pager;
        $currentPage = $pager ? (int) $pager->getCurrentPage('loginActivity') : $page;
        $pageCount = $pager ? (int) $pager->getPageCount('loginActivity') : (int) max(1, ceil($totalActivities / $perPage));

        $normalized = array_map(static function ($activity) {
            if (!is_array($activity)) {
                return [];
            }

            return [
                'user_id'     => $activity['user_id'] ?? null,
                'email'       => $activity['email'] ?? null,
                'login_time'  => $activity['login_time'] ?? null,
                'logout_time' => $activity['logout_time'] ?? null,
                'ip_address'  => $activity['ip_address'] ?? null,
                'user_agent'  => $activity['user_agent'] ?? null,
            ];
        }, $activities);

        return [
            'activities' => $normalized,
            'pagination' => [
                'total'       => $totalActivities,
                'perPage'     => $perPage,
                'currentPage' => $currentPage,
                'pageCount'   => $pageCount,
                'hasNext'     => $currentPage < $pageCount,
                'hasPrevious' => $currentPage > 1,
            ],
        ];
    }
}
