<?php
/**
 * Simple but secure authentication system
 * Compatible with PHP 5.6+ (maximum compatibility)
 */

class Auth
{
    private $configFile;
    private $config;
    private $maxAttempts = 5;
    private $lockoutTime = 900;
    private $passwordAlgo;

    public function __construct($configFile = null)
    {
        if ($configFile === null) {
            $this->configFile = __DIR__ . '/../auth_config.php';
        } else {
            $this->configFile = $configFile;
        }

        // Use Argon2ID if available, fallback to bcrypt
        if (defined('PASSWORD_ARGON2ID')) {
            $this->passwordAlgo = PASSWORD_ARGON2ID;
        } else {
            $this->passwordAlgo = PASSWORD_BCRYPT;
        }

        $this->loadConfig();
    }

    private function loadConfig()
    {
        if (file_exists($this->configFile)) {
            $this->config = require $this->configFile;
        } else {
            $this->config = array(
                'users' => array(),
                'failed_attempts' => array(),
            );
        }
    }

    private function saveConfig()
    {
        $content = "<?php\nreturn " . var_export($this->config, true) . ";\n";
        file_put_contents($this->configFile, $content);
        @chmod($this->configFile, 0600);
    }

    public function createUser($username, $password)
    {
        if (isset($this->config['users'][$username])) {
            return false;
        }

        $this->config['users'][$username] = array(
            'password_hash' => $this->hashPassword($password),
            'created_at' => time(),
        );

        $this->saveConfig();
        return true;
    }

    public function changePassword($username, $oldPassword, $newPassword)
    {
        if (!$this->verifyPassword($username, $oldPassword)) {
            return false;
        }

        $this->config['users'][$username]['password_hash'] = $this->hashPassword($newPassword);
        $this->saveConfig();
        return true;
    }

    private function hashPassword($password)
    {
        if ($this->passwordAlgo === PASSWORD_ARGON2ID) {
            return password_hash($password, PASSWORD_ARGON2ID, array(
                'memory_cost' => 65536,
                'time_cost' => 4,
                'threads' => 1,
            ));
        }
        return password_hash($password, PASSWORD_BCRYPT, array('cost' => 12));
    }

    private function verifyPassword($username, $password)
    {
        if (!isset($this->config['users'][$username])) {
            $this->hashPassword($password);
            return false;
        }
        return password_verify($password, $this->config['users'][$username]['password_hash']);
    }

    private function isLockedOut($ip)
    {
        if (!isset($this->config['failed_attempts'][$ip])) {
            return false;
        }

        $attempts = $this->config['failed_attempts'][$ip];
        $lockoutTime = $this->lockoutTime;

        $filtered = array();
        foreach ($attempts as $time) {
            if ($time > time() - $lockoutTime) {
                $filtered[] = $time;
            }
        }
        $this->config['failed_attempts'][$ip] = $filtered;

        return count($filtered) >= $this->maxAttempts;
    }

    private function recordFailedAttempt($ip)
    {
        if (!isset($this->config['failed_attempts'][$ip])) {
            $this->config['failed_attempts'][$ip] = array();
        }
        $this->config['failed_attempts'][$ip][] = time();
        $this->saveConfig();
    }

    private function clearFailedAttempts($ip)
    {
        unset($this->config['failed_attempts'][$ip]);
        $this->saveConfig();
    }

    public function login($username, $password, $ip)
    {
        if ($this->isLockedOut($ip)) {
            return array(
                'success' => false,
                'message' => 'Too many failed attempts. Please try again later.',
                'locked' => true,
            );
        }

        if ($this->verifyPassword($username, $password)) {
            $this->clearFailedAttempts($ip);
            $token = $this->generateSessionToken();

            return array(
                'success' => true,
                'message' => 'Login successful',
                'token' => $token,
                'username' => $username,
            );
        }

        $this->recordFailedAttempt($ip);

        $attempts = isset($this->config['failed_attempts'][$ip]) ? $this->config['failed_attempts'][$ip] : array();
        $remaining = $this->maxAttempts - count($attempts);

        return array(
            'success' => false,
            'message' => "Invalid username or password. {$remaining} attempts remaining.",
            'locked' => false,
        );
    }

    private function generateSessionToken()
    {
        if (function_exists('random_bytes')) {
            return bin2hex(random_bytes(32));
        }
        return bin2hex(openssl_random_pseudo_bytes(32));
    }

    public function startSession($username, $token)
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        session_regenerate_id(true);

        $_SESSION['authenticated'] = true;
        $_SESSION['username'] = $username;
        $_SESSION['token'] = $token;
        $_SESSION['login_time'] = time();
        $_SESSION['last_activity'] = time();
    }

    public function isAuthenticated($timeout = 3600)
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        if (empty($_SESSION['authenticated'])) {
            return false;
        }

        $lastActivity = isset($_SESSION['last_activity']) ? $_SESSION['last_activity'] : 0;
        if (time() - $lastActivity > $timeout) {
            $this->logout();
            return false;
        }

        $_SESSION['last_activity'] = time();
        return true;
    }

    public function logout()
    {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }

        $_SESSION = array();

        if (isset($_COOKIE[session_name()])) {
            setcookie(session_name(), '', time() - 3600, '/');
        }

        session_destroy();
    }

    public function getCurrentUser()
    {
        if (!$this->isAuthenticated()) {
            return null;
        }
        return isset($_SESSION['username']) ? $_SESSION['username'] : null;
    }

    public function hasUsers()
    {
        return !empty($this->config['users']);
    }

    public static function getClientIP()
    {
        $headers = array('HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'REMOTE_ADDR');

        foreach ($headers as $header) {
            if (!empty($_SERVER[$header])) {
                $ip = $_SERVER[$header];
                if (strpos($ip, ',') !== false) {
                    $parts = explode(',', $ip);
                    $ip = trim($parts[0]);
                }
                if (filter_var($ip, FILTER_VALIDATE_IP)) {
                    return $ip;
                }
            }
        }

        return '0.0.0.0';
    }
}
