<?php
/**
 * Auth - Kimlik Doğrulama ve Güvenlik Sınıfı
 * Aegean Dominance Admin Panel
 * 
 * Brute-force koruması, session hijacking koruması, CSRF token yönetimi
 */

declare(strict_types=1);

class Auth
{
    private Database $db;
    private const MAX_LOGIN_ATTEMPTS = 5;
    private const LOCKOUT_TIME = 900; // 15 dakika
    private const SESSION_LIFETIME = 3600; // 1 saat
    private const REMEMBER_ME_DAYS = 30;
    
    public function __construct()
    {
        $this->db = Database::getInstance();
    }
    
    // =========================================================================
    // LOGIN / LOGOUT
    // =========================================================================
    
    /**
     * Kullanıcı girişi
     */
    public function login(string $username, string $password, bool $remember = false): array
    {
        try {
            $ip = $this->getClientIP();
            
            // Brute-force kontrolü
            if ($this->isLockedOut($ip)) {
                $remaining = $this->getLockoutRemaining($ip);
                return [
                    'success' => false,
                    'error' => "Çok fazla başarısız deneme. {$remaining} dakika sonra tekrar deneyin."
                ];
            }
            
            // Kullanıcıyı bul
            $user = $this->db->fetchOne(
                "SELECT * FROM admins WHERE username = ? AND is_active = 1",
                [$username]
            );
            
            if (!$user || !password_verify($password, $user['password'])) {
                $this->recordFailedAttempt($ip);
                return [
                    'success' => false,
                    'error' => 'Kullanıcı adı veya şifre hatalı.'
                ];
            }
            
            // Başarılı giriş - denemeleri temizle
            $this->clearAttempts($ip);
            
            // Session oluştur
            $this->createSession($user, $remember);
            
            // Son giriş güncelle
            $this->db->execute(
                "UPDATE admins SET last_login = NOW() WHERE id = ?",
                [$user['id']]
            );
            
            return [
                'success' => true,
                'user' => [
                    'id' => $user['id'],
                    'username' => $user['username'],
                    'email' => $user['email']
                ]
            ];
            
        } catch (Exception $e) {
            error_log("Auth::login error: " . $e->getMessage());
            return [
                'success' => false,
                'error' => 'Sistem hatası oluştu.'
            ];
        }
    }
    
    /**
     * Çıkış yap
     */
    public function logout(): void
    {
        try {
            // Session token varsa sil
            if (isset($_SESSION['session_token'])) {
                $this->db->execute(
                    "DELETE FROM admin_sessions WHERE session_id = ?",
                    [$_SESSION['session_token']]
                );
            }
            
            // Remember me cookie sil
            if (isset($_COOKIE['remember_token'])) {
                setcookie('remember_token', '', time() - 3600, '/', '', true, true);
            }
            
            // Session temizle
            $_SESSION = [];
            session_destroy();
            
        } catch (Exception $e) {
            error_log("Auth::logout error: " . $e->getMessage());
        }
    }
    
    // =========================================================================
    // SESSION MANAGEMENT
    // =========================================================================
    
    /**
     * Session oluştur
     */
    private function createSession(array $user, bool $remember): void
    {
        // Session regenerate (hijacking koruması)
        session_regenerate_id(true);
        
        $sessionToken = bin2hex(random_bytes(32));
        $ip = $this->getClientIP();
        $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';
        $expiresAt = date('Y-m-d H:i:s', time() + self::SESSION_LIFETIME);
        
        // Veritabanına kaydet
        $this->db->execute(
            "INSERT INTO admin_sessions (admin_id, session_id, ip_address, user_agent, expires_at) 
             VALUES (?, ?, ?, ?, ?)",
            [$user['id'], $sessionToken, $ip, $userAgent, $expiresAt]
        );
        
        // Session değişkenleri
        $_SESSION['user_id'] = $user['id'];
        $_SESSION['username'] = $user['username'];
        $_SESSION['session_token'] = $sessionToken;
        $_SESSION['ip_address'] = $ip;
        $_SESSION['user_agent'] = md5($userAgent);
        $_SESSION['last_activity'] = time();
        
        // CSRF token oluştur
        $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        
        // Remember me
        if ($remember) {
            $rememberToken = bin2hex(random_bytes(32));
            $expiry = time() + (86400 * self::REMEMBER_ME_DAYS);
            
            $this->db->execute(
                "UPDATE admins SET remember_token = ?, remember_expires = ? WHERE id = ?",
                [$rememberToken, date('Y-m-d H:i:s', $expiry), $user['id']]
            );
            
            setcookie(
                'remember_token',
                $rememberToken,
                [
                    'expires' => $expiry,
                    'path' => '/',
                    'secure' => true,
                    'httponly' => true,
                    'samesite' => 'Strict'
                ]
            );
        }
    }
    
    /**
     * Oturum kontrolü
     */
    public function check(): bool
    {
        try {
            // Session var mı?
            if (!isset($_SESSION['user_id']) || !isset($_SESSION['session_token'])) {
                return $this->tryRememberMe();
            }
            
            // Session hijacking kontrolü
            if (!$this->validateSession()) {
                $this->logout();
                return false;
            }
            
            // Session timeout kontrolü
            if (time() - ($_SESSION['last_activity'] ?? 0) > self::SESSION_LIFETIME) {
                $this->logout();
                return false;
            }
            
            // Activity güncelle
            $_SESSION['last_activity'] = time();
            
            return true;
            
        } catch (Exception $e) {
            error_log("Auth::check error: " . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Session doğrulama (hijacking koruması)
     */
    private function validateSession(): bool
    {
        $ip = $this->getClientIP();
        $userAgent = md5($_SERVER['HTTP_USER_AGENT'] ?? '');
        
        // IP ve User-Agent eşleşmesi
        if ($_SESSION['ip_address'] !== $ip || $_SESSION['user_agent'] !== $userAgent) {
            return false;
        }
        
        // Veritabanında session kontrolü
        $session = $this->db->fetchOne(
            "SELECT * FROM admin_sessions WHERE session_id = ? AND expires_at > NOW()",
            [$_SESSION['session_token']]
        );
        
        return $session !== null;
    }
    
    /**
     * Remember me ile giriş dene
     */
    private function tryRememberMe(): bool
    {
        if (!isset($_COOKIE['remember_token'])) {
            return false;
        }
        
        try {
            $user = $this->db->fetchOne(
                "SELECT * FROM admins WHERE remember_token = ? AND remember_expires > NOW() AND is_active = 1",
                [$_COOKIE['remember_token']]
            );
            
            if ($user) {
                $this->createSession($user, true);
                return true;
            }
            
        } catch (Exception $e) {
            error_log("Auth::tryRememberMe error: " . $e->getMessage());
        }
        
        return false;
    }
    
    // =========================================================================
    // BRUTE-FORCE PROTECTION
    // =========================================================================
    
    /**
     * Başarısız giriş kaydet
     */
    private function recordFailedAttempt(string $ip): void
    {
        $this->db->execute(
            "INSERT INTO login_attempts (ip_address) VALUES (?)",
            [$ip]
        );
    }
    
    /**
     * Kilitli mi kontrol
     */
    private function isLockedOut(string $ip): bool
    {
        $since = date('Y-m-d H:i:s', time() - self::LOCKOUT_TIME);
        
        $count = (int) $this->db->fetchColumn(
            "SELECT COUNT(*) FROM login_attempts WHERE ip_address = ? AND attempted_at > ?",
            [$ip, $since]
        );
        
        return $count >= self::MAX_LOGIN_ATTEMPTS;
    }
    
    /**
     * Kilit kalan süre (dakika)
     */
    private function getLockoutRemaining(string $ip): int
    {
        $since = date('Y-m-d H:i:s', time() - self::LOCKOUT_TIME);
        
        $lastAttempt = $this->db->fetchColumn(
            "SELECT MAX(attempted_at) FROM login_attempts WHERE ip_address = ? AND attempted_at > ?",
            [$ip, $since]
        );
        
        if ($lastAttempt) {
            $unlockTime = strtotime($lastAttempt) + self::LOCKOUT_TIME;
            return (int) ceil(($unlockTime - time()) / 60);
        }
        
        return 0;
    }
    
    /**
     * Başarısız denemeleri temizle
     */
    private function clearAttempts(string $ip): void
    {
        $this->db->execute(
            "DELETE FROM login_attempts WHERE ip_address = ?",
            [$ip]
        );
    }
    
    // =========================================================================
    // CSRF PROTECTION
    // =========================================================================
    
    /**
     * CSRF token al
     */
    public function getCsrfToken(): string
    {
        if (!isset($_SESSION['csrf_token'])) {
            $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        }
        return $_SESSION['csrf_token'];
    }
    
    /**
     * CSRF token doğrula
     */
    public function validateCsrf(string $token): bool
    {
        return isset($_SESSION['csrf_token']) && hash_equals($_SESSION['csrf_token'], $token);
    }
    
    /**
     * CSRF hidden input
     */
    public function csrfField(): string
    {
        return '<input type="hidden" name="csrf_token" value="' . $this->getCsrfToken() . '">';
    }
    
    // =========================================================================
    // HELPERS
    // =========================================================================
    
    /**
     * Gerçek IP adresi
     */
    private function getClientIP(): string
    {
        $headers = ['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) {
                    $ip = trim(explode(',', $ip)[0]);
                }
                if (filter_var($ip, FILTER_VALIDATE_IP)) {
                    return $ip;
                }
            }
        }
        
        return $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
    }
    
    /**
     * Mevcut kullanıcı
     */
    public function user(): ?array
    {
        if (!$this->check()) {
            return null;
        }
        
        return $this->db->fetchOne(
            "SELECT id, username, email, created_at FROM admins WHERE id = ?",
            [$_SESSION['user_id']]
        );
    }
    
    /**
     * Şifre hash
     */
    public static function hashPassword(string $password): string
    {
        return password_hash($password, PASSWORD_ARGON2ID);
    }
    
    /**
     * Eski session'ları temizle (cron job)
     */
    public function cleanupSessions(): int
    {
        $count = $this->db->execute("DELETE FROM admin_sessions WHERE expires_at < NOW()");
        $count += $this->db->execute("DELETE FROM login_attempts WHERE attempted_at < DATE_SUB(NOW(), INTERVAL 1 DAY)");
        return $count;
    }
    
    /**
     * Giriş yapılmış mı? (alias for check)
     */
    public function isLoggedIn(): bool
    {
        return $this->check();
    }
    
    /**
     * Giriş zorunlu - değilse login'e yönlendir
     */
    public function requireLogin(): void
    {
        if (!$this->check()) {
            header('Location: login.php');
            exit;
        }
    }
    
    /**
     * Mevcut admin bilgilerini al
     */
    public function getCurrentAdmin(): ?array
    {
        if (!$this->check()) {
            return null;
        }
        
        return $this->db->fetchOne(
            "SELECT id, username, email, full_name, role, last_login, created_at FROM admins WHERE id = ?",
            [$_SESSION['user_id']]
        );
    }
    
    /**
     * CSRF token oluştur (alias for getCsrfToken)
     */
    public function generateCsrf(): string
    {
        return $this->getCsrfToken();
    }
}

/**
 * Auth helper
 */
function auth(): Auth
{
    static $instance = null;
    if ($instance === null) {
        $instance = new Auth();
    }
    return $instance;
}
