<?php
/**
 * ZLO Platform - Authentication Controller
 */

declare(strict_types=1);

require_once __DIR__ . '/../models/User.php';
require_once __DIR__ . '/../core/Router.php';

class AuthController
{
    private User $userModel;
    private Security $security;
    
    public function __construct()
    {
        $this->userModel = new User();
        $this->security = new Security();
    }
    
    /**
     * Login user
     */
    public function login(array $params): array
    {
        $body = Router::getBody();
        
        // Validate input
        if (empty($body['email']) || empty($body['password'])) {
            http_response_code(400);
            return ['error' => 'Email and password are required'];
        }
        
        $email = $body['email'];
        $password = $body['password'];
        $remember = $body['remember'] ?? false;
        
        // Rate limiting
        if (!$this->security->checkRateLimit($email, 5, 900)) {
            http_response_code(429);
            return ['error' => 'Too many login attempts. Please try again later.'];
        }
        
        // Authenticate
        $user = $this->userModel->authenticate($email, $password);
        
        if (!$user) {
            http_response_code(401);
            return ['error' => 'Invalid credentials'];
        }
        
        // Check if user is active
        if ($user['status'] !== 'active') {
            http_response_code(403);
            return ['error' => 'Account is not active'];
        }
        
        // Reset rate limit on success
        $this->security->resetRateLimit($email);
        
        // Generate tokens
        $accessToken = $this->generateAccessToken($user);
        $refreshToken = null;
        
        if ($remember) {
            $refreshToken = $this->userModel->generateRememberToken($user['id']);
        }
        
        // Log successful login
        $this->security->logEvent('login_success', [
            'user_id' => $user['id'],
            'email' => $email
        ]);
        
        return [
            'user' => $user,
            'access_token' => $accessToken,
            'refresh_token' => $refreshToken,
            'expires_in' => 7200 // 2 hours
        ];
    }
    
    /**
     * Logout user
     */
    public function logout(array $params): array
    {
        $token = Router::getAuthToken();
        
        if ($token) {
            // Invalidate token (in production, use Redis or database)
            // For now, just log the event
            $this->security->logEvent('logout', ['token' => substr($token, 0, 10) . '...']);
        }
        
        // Clear session
        session_destroy();
        
        return ['message' => 'Logged out successfully'];
    }
    
    /**
     * Refresh access token
     */
    public function refresh(array $params): array
    {
        $body = Router::getBody();
        
        if (empty($body['refresh_token'])) {
            http_response_code(400);
            return ['error' => 'Refresh token is required'];
        }
        
        $user = $this->userModel->findByRememberToken($body['refresh_token']);
        
        if (!$user) {
            http_response_code(401);
            return ['error' => 'Invalid refresh token'];
        }
        
        $accessToken = $this->generateAccessToken($user);
        
        return [
            'access_token' => $accessToken,
            'expires_in' => 7200
        ];
    }
    
    /**
     * Get current user
     */
    public function me(array $params): ?array
    {
        $user = $this->getAuthenticatedUser();
        
        if (!$user) {
            http_response_code(401);
            return ['error' => 'Unauthorized'];
        }
        
        return $user;
    }
    
    /**
     * Change password
     */
    public function changePassword(array $params): array
    {
        $user = $this->getAuthenticatedUser();
        
        if (!$user) {
            http_response_code(401);
            return ['error' => 'Unauthorized'];
        }
        
        $body = Router::getBody();
        
        if (empty($body['current_password']) || empty($body['new_password'])) {
            http_response_code(400);
            return ['error' => 'Current password and new password are required'];
        }
        
        // Verify current password
        $sql = "SELECT password FROM users WHERE id = ?";
        $db = new Database();
        $result = $db->fetchOne($sql, [$user['id']]);
        
        if (!$this->security->verifyPassword($body['current_password'], $result['password'])) {
            http_response_code(400);
            return ['error' => 'Current password is incorrect'];
        }
        
        // Update password
        $this->userModel->update($user['id'], [
            'password' => $body['new_password']
        ]);
        
        $this->security->logEvent('password_changed', ['user_id' => $user['id']]);
        
        return ['message' => 'Password changed successfully'];
    }
    
    /**
     * Generate access token
     */
    private function generateAccessToken(array $user): string
    {
        $header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
        $time = time();
        $payload = json_encode([
            'iss' => 'zlo-platform',
            'iat' => $time,
            'exp' => $time + 7200,
            'sub' => $user['id'],
            'email' => $user['email'],
            'role' => $user['role']['name'] ?? 'user'
        ]);
        
        $base64Header = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
        $base64Payload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));
        
        $signature = hash_hmac('sha256', $base64Header . "." . $base64Payload, $this->getSecretKey(), true);
        $base64Signature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
        
        return $base64Header . "." . $base64Payload . "." . $base64Signature;
    }
    
    /**
     * Verify access token
     */
    public function verifyToken(string $token): ?array
    {
        $parts = explode('.', $token);
        
        if (count($parts) !== 3) {
            return null;
        }
        
        [$base64Header, $base64Payload, $base64Signature] = $parts;
        
        $signature = hash_hmac('sha256', $base64Header . "." . $base64Payload, $this->getSecretKey(), true);
        $expectedSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));
        
        if (!hash_equals($expectedSignature, $base64Signature)) {
            return null;
        }
        
        $payload = json_decode(base64_decode(str_replace(['-', '_'], ['+', '/'], $base64Payload)), true);
        
        if (!$payload || $payload['exp'] < time()) {
            return null;
        }
        
        return $payload;
    }
    
    /**
     * Get authenticated user from token
     */
    public function getAuthenticatedUser(): ?array
    {
        $token = Router::getAuthToken();
        
        if (!$token) {
            return null;
        }
        
        $payload = $this->verifyToken($token);
        
        if (!$payload) {
            return null;
        }
        
        return $this->userModel->find($payload['sub']);
    }
    
    /**
     * Check if user has permission
     */
    public function hasPermission(string $permission): bool
    {
        $user = $this->getAuthenticatedUser();
        
        if (!$user) {
            return false;
        }
        
        return $this->userModel->hasPermission($user['id'], $permission);
    }
    
    /**
     * Require authentication middleware
     */
    public static function requireAuth(): void
    {
        $controller = new self();
        
        if (!$controller->getAuthenticatedUser()) {
            http_response_code(401);
            echo json_encode(['error' => 'Unauthorized']);
            exit;
        }
    }
    
    /**
     * Require permission middleware
     */
    public static function requirePermission(string $permission): void
    {
        $controller = new self();
        
        if (!$controller->hasPermission($permission)) {
            http_response_code(403);
            echo json_encode(['error' => 'Forbidden']);
            exit;
        }
    }
    
    /**
     * Get secret key
     */
    private function getSecretKey(): string
    {
        return $_ENV['JWT_SECRET'] ?? 'your-secret-key-change-in-production';
    }
}
