<?php
/**
 * RoVo Real Estate Platform
 * Authentication System
 * PHP 8.2+ Compatible
 */

if (!defined('ROVO_APP')) {
    define('ROVO_APP', true);
}

require_once 'config.php';

class Auth {
    private $db;
    private $errors = [];
    
    public function __construct() {
        //$this->db = Database::getInstance();
        $db = Database::getInstance();
        $this->db = $db;
    }
    
    /**
     * Register a new user
     */
    public function register($data) {
        $this->errors = [];
        
        // Validate input
        if (!$this->validateRegisterInput($data)) {
            return false;
        }
        
        // Check if email exists
        if ($this->emailExists($data['email'])) {
            $this->errors[] = "Email address already registered";
            return false;
        }
        
        // Check if phone exists
        if ($this->phoneExists($data['phone'])) {
            $this->errors[] = "Phone number already registered";
            return false;
        }
        
        try {
            // Hash password
            $password_hash = Security::hashPassword($data['password']);
            
            // Prepare SQL
            $sql = "INSERT INTO users (first_name, last_name, email, phone, password_hash, status) 
                    VALUES (?, ?, ?, ?, ?, 'pending')";
            
            $params = [
                Security::sanitizeInput($data['first_name']),
                Security::sanitizeInput($data['last_name']),
                strtolower(trim($data['email'])),
                $data['phone'],
                $password_hash
            ];
            
            $this->db->execute($sql, $params);
            $user_id = $this->db->lastInsertId();
            
            // Log activity
            $this->logActivity($user_id, 'register', 'user', $user_id, 'User registered');
            
            // Send verification email (implement this separately)
            // $this->sendVerificationEmail($data['email']);
            
            return $user_id;
            
        } catch (Exception $e) {
            $this->errors[] = "Registration failed. Please try again.";
            error_log("Registration error: " . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Login user
     */
    public function login($email, $password, $remember = false) {
        $this->errors = [];
        
        // Sanitize email
        $email = strtolower(trim($email));
        
        // Get user
        $sql = "SELECT * FROM users WHERE email = ? LIMIT 1";
        $user = $this->db->fetchOne($sql, [$email]);
        
        if (!$user) {
            $this->errors[] = "Invalid email or password";
            return false;
        }
        
        // Check if account is locked
        if (!Security::checkLoginAttempts($user['id'])) {
            $this->errors[] = "Account temporarily locked due to too many failed login attempts";
            return false;
        }
        
        // Verify password
        if (!Security::verifyPassword($password, $user['password_hash'])) {
            Security::recordLoginAttempt($user['id'], false);
            $this->errors[] = "Invalid email or password forbidden";
            return false;
        }
        
        // Check account status
        if ($user['status'] === 'suspended') {
            $this->errors[] = "Your account has been suspended. Please contact support.";
            return false;
        }
        
        if ($user['status'] === 'banned') {
            $this->errors[] = "Your account has been banned.";
            return false;
        }
        
        // Login successful
        Security::recordLoginAttempt($user['id'], true);
        
        // Set session
        $this->setUserSession($user);
        
        // Create session token
        $this->createSessionToken($user['id'], $remember);
        
        // Log activity
        $this->logActivity($user['id'], 'login', 'user', $user['id'], 'User logged in');
        
        return true;
    }
    
    /**
     * Logout user
     */
    public function logout() {
        if ($this->isLoggedIn()) {
            $user_id = $_SESSION['user_id'];
            
            // Delete session token
            if (isset($_COOKIE['session_token'])) {
                $sql = "DELETE FROM user_sessions WHERE session_token = ?";
                $this->db->execute($sql, [$_COOKIE['session_token']]);
                setcookie('session_token', '', time() - 3600, '/');
            }
            
            // Log activity
            $this->logActivity($user_id, 'logout', 'user', $user_id, 'User logged out');
        }
        
        // Destroy session
        session_unset();
        session_destroy();
        session_write_close();
        setcookie(session_name(), '', 0, '/');
        session_regenerate_id(true);
    }
    
    /**
     * Check if user is logged in
     */
    public function isLoggedIn() {
        if (isset($_SESSION['user_id']) && isset($_SESSION['logged_in']) && $_SESSION['logged_in'] === true) {
            return true;
        }
        
        // Check for remember me cookie
        if (isset($_COOKIE['session_token'])) {
            return $this->validateSessionToken($_COOKIE['session_token']);
        }
        
        return false;
    }
    
    /**
     * Check if user has specific role
     */
    public function hasRole($role) {
        if (!$this->isLoggedIn()) {
            return false;
        }
        
        if (is_array($role)) {
            return in_array($_SESSION['user_role'], $role);
        }
        
        return $_SESSION['user_role'] === $role;
    }
    
    /**
     * Check if user is admin
     */
    public function isAdmin() {
        return $this->hasRole(['super_admin', 'admin', 'junior_admin']);
    }
    
    /**
     * Get current user
     */
    public function getCurrentUser() {
        if (!$this->isLoggedIn()) {
            return null;
        }
        
        $sql = "SELECT * FROM users WHERE id = ?";
        return $this->db->fetchOne($sql, [$_SESSION['user_id']]);
    }
    
    /**
     * Get user permissions
     */
    public function getUserPermissions($user_id = null) {
        if ($user_id === null) {
            $user_id = $_SESSION['user_id'] ?? null;
        }
        
        if (!$user_id) {
            return null;
        }
        
        $sql = "SELECT * FROM admin_permissions WHERE admin_id = ?";
        return $this->db->fetchOne($sql, [$user_id]);
    }
    
    /**
     * Check if user has permission
     */
    public function hasPermission($permission) {
        if (!$this->isAdmin()) {
            return false;
        }
        
        // Super admin has all permissions
        if ($this->hasRole('super_admin')) {
            return true;
        }
        
        $permissions = $this->getUserPermissions();
        if (!$permissions) {
            return false;
        }
        
        return isset($permissions[$permission]) && $permissions[$permission] == 1;
    }
    
    /**
     * Create admin user
     */
    public function createAdmin($data, $created_by) {
        if (!$this->hasPermission('can_manage_users')) {
            $this->errors[] = "You don't have permission to create admin users";
            return false;
        }
        
        // Validate input
        if (!$this->validateRegisterInput($data)) {
            return false;
        }
        
        // Check role
        $allowed_roles = ['admin', 'junior_admin'];
        if (!in_array($data['role'], $allowed_roles)) {
            $this->errors[] = "Invalid role selected";
            return false;
        }
        
        try {
            $this->db->beginTransaction();
            
            // Create user
            $password_hash = Security::hashPassword($data['password']);
            
            $sql = "INSERT INTO users (first_name, last_name, email, phone, password_hash, role, status, created_by) 
                    VALUES (?, ?, ?, ?, ?, ?, 'active', ?)";
            
            $params = [
                Security::sanitizeInput($data['first_name']),
                Security::sanitizeInput($data['last_name']),
                strtolower(trim($data['email'])),
                $data['phone'],
                $password_hash,
                $data['role'],
                $created_by
            ];
            
            $this->db->execute($sql, $params);
            $user_id = $this->db->lastInsertId();
            
            // Set permissions based on role
            $permissions = $this->getDefaultPermissions($data['role']);
            
            $sql = "INSERT INTO admin_permissions (admin_id, can_create, can_edit, can_delete, can_view, 
                    can_manage_users, can_manage_payments, can_manage_properties, can_verify_documents) 
                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
            
            $this->db->execute($sql, [
                $user_id,
                $permissions['can_create'],
                $permissions['can_edit'],
                $permissions['can_delete'],
                $permissions['can_view'],
                $permissions['can_manage_users'],
                $permissions['can_manage_payments'],
                $permissions['can_manage_properties'],
                $permissions['can_verify_documents']
            ]);
            
            $this->db->commit();
            
            // Log activity
            $this->logActivity($created_by, 'create_admin', 'user', $user_id, "Admin user created: {$data['email']}");
            
            return $user_id;
            
        } catch (Exception $e) {
            $this->db->rollBack();
            $this->errors[] = "Failed to create admin user";
            error_log("Create admin error: " . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Suspend user
     */
    public function suspendUser($user_id, $suspended_by) {
        if (!$this->hasPermission('can_manage_users')) {
            $this->errors[] = "You don't have permission to suspend users";
            return false;
        }
        
        $sql = "UPDATE users SET status = 'suspended' WHERE id = ?";
        $result = $this->db->execute($sql, [$user_id]);
        
        if ($result) {
            $this->logActivity($suspended_by, 'suspend_user', 'user', $user_id, "User suspended");
        }
        
        return $result > 0;
    }
    
    /**
     * Activate user
     */
    public function activateUser($user_id, $activated_by) {
        if (!$this->hasPermission('can_manage_users')) {
            $this->errors[] = "You don't have permission to activate users";
            return false;
        }
        
        $sql = "UPDATE users SET status = 'active' WHERE id = ?";
        $result = $this->db->execute($sql, [$user_id]);
        
        if ($result) {
            $this->logActivity($activated_by, 'activate_user', 'user', $user_id, "User activated");
        }
        
        return $result > 0;
    }
    
    /**
     * Delete user (Super admin only)
     */
    public function deleteUser($user_id, $deleted_by) {
        if (!$this->hasRole('super_admin')) {
            $this->errors[] = "Only super admin can delete users";
            return false;
        }
        
        $sql = "DELETE FROM users WHERE id = ? AND role != 'super_admin'";
        $result = $this->db->execute($sql, [$user_id]);
        
        if ($result) {
            $this->logActivity($deleted_by, 'delete_user', 'user', $user_id, "User deleted");
        }
        
        return $result > 0;
    }
    
    // ============================
    // PRIVATE HELPER METHODS
    // ============================
    
    private function validateRegisterInput($data) {
        if (empty($data['first_name'])) {
            $this->errors[] = "First name is required";
        }
        
        if (empty($data['last_name'])) {
            $this->errors[] = "Last name is required";
        }
        
        if (empty($data['email']) || !Security::validateEmail($data['email'])) {
            $this->errors[] = "Valid email is required";
        }
        
        if (empty($data['phone']) || !Security::validatePhone($data['phone'])) {
            $this->errors[] = "Valid Nigerian phone number is required";
        }
        
        if (empty($data['password']) || strlen($data['password']) < 8) {
            $this->errors[] = "Password must be at least 8 characters";
        }
        
        if (isset($data['confirm_password']) && $data['password'] !== $data['confirm_password']) {
            $this->errors[] = "Passwords do not match";
        }
        
        return empty($this->errors);
    }
    
    private function emailExists($email) {
        $sql = "SELECT id FROM users WHERE email = ?";
        return $this->db->fetchOne($sql, [strtolower(trim($email))]) !== false;
    }
    
    private function phoneExists($phone) {
        $sql = "SELECT id FROM users WHERE phone = ?";
        return $this->db->fetchOne($sql, [$phone]) !== false;
    }
    
    private function setUserSession($user) {
        session_regenerate_id(true);
        
        $_SESSION['user_id'] = $user['id'];
        $_SESSION['user_email'] = $user['email'];
        $_SESSION['user_name'] = $user['first_name'] . ' ' . $user['last_name'];
        $_SESSION['user_role'] = $user['role'];
        $_SESSION['logged_in'] = true;
        $_SESSION['login_time'] = time();
    }
    
    private function createSessionToken($user_id, $remember = false) {
        $token = Security::generateToken();
        $ip_address = Security::getClientIP();
        $user_agent = $_SERVER['HTTP_USER_AGENT'] ?? '';
        $expires_at = date('Y-m-d H:i:s', strtotime($remember ? '+30 days' : '+1 day'));
        
        $sql = "INSERT INTO user_sessions (user_id, session_token, ip_address, user_agent, expires_at) 
                VALUES (?, ?, ?, ?, ?)";
        
        $this->db->execute($sql, [$user_id, $token, $ip_address, $user_agent, $expires_at]);
        
        if ($remember) {
            setcookie('session_token', $token, time() + (30 * 24 * 60 * 60), '/', '', true, true);
        }
    }
    
    private function validateSessionToken($token) {
        $sql = "SELECT s.*, u.* FROM user_sessions s 
                JOIN users u ON s.user_id = u.id 
                WHERE s.session_token = ? AND s.expires_at > NOW() AND u.status = 'active'";
        
        $session = $this->db->fetchOne($sql, [$token]);
        
        if ($session) {
            $this->setUserSession($session);
            return true;
        }
        
        return false;
    }
    
    private function getDefaultPermissions($role) {
        $permissions = [
            'junior_admin' => [
                'can_create' => 0,
                'can_edit' => 0,
                'can_delete' => 0,
                'can_view' => 1,
                'can_manage_users' => 0,
                'can_manage_payments' => 0,
                'can_manage_properties' => 0,
                'can_verify_documents' => 0
            ],
            'admin' => [
                'can_create' => 1,
                'can_edit' => 1,
                'can_delete' => 0,
                'can_view' => 1,
                'can_manage_users' => 0,
                'can_manage_payments' => 1,
                'can_manage_properties' => 1,
                'can_verify_documents' => 1
            ]
        ];
        
        return $permissions[$role] ?? $permissions['junior_admin'];
    }
    
    private function logActivity($user_id, $action, $entity_type, $entity_id, $description) {
        $sql = "INSERT INTO activity_logs (user_id, action, entity_type, entity_id, description, ip_address, user_agent) 
                VALUES (?, ?, ?, ?, ?, ?, ?)";
        
        $params = [
            $user_id,
            $action,
            $entity_type,
            $entity_id,
            $description,
            Security::getClientIP(),
            $_SERVER['HTTP_USER_AGENT'] ?? ''
        ];
        
        try {
            $this->db->execute($sql, $params);
        } catch (Exception $e) {
            error_log("Activity log error: " . $e->getMessage());
        }
    }
    
    public function getErrors() {
        return $this->errors;
    }
}

// Initialize auth instance
$auth = new Auth();