<?php

namespace App\Middleware;

use App\Utils\JWT;
use App\Utils\View;

class ApiMiddleware
{
    public function handle()
    {
        $headers = getallheaders();

        // Handle case-insensitive headers and Proxy fallbacks
        $authHeader = $headers['Authorization'] ?? $headers['authorization'] ?? $_SERVER['HTTP_AUTHORIZATION'] ?? '';
        $machineId = $headers['X-Machine-ID'] ?? $headers['x-machine-id'] ?? $_SERVER['HTTP_X_MACHINE_ID'] ?? '';

        if (!preg_match('/Bearer\s(\S+)/', $authHeader, $matches)) {
            View::json(['error' => 'Serial Key not provided'], 401);
            return false;
        }

        $serialKey = $matches[1];

        if (empty($machineId)) {
            View::json(['error' => 'Machine ID not provided'], 400);
            return false;
        }

        try {
            $conn = \App\Config\Database::getInstance()->getConnection();

            // Find server by Serial Key and join with client to check both statuses
            $stmt = $conn->prepare("
                SELECT s.id, s.machine_id, s.status, s.ip_v4, s.client_id, c.status as client_status 
                FROM servers s 
                JOIN clients c ON s.client_id = c.id 
                WHERE s.serial_key = :serial
            ");
            $stmt->execute(['serial' => $serialKey]);
            $server = $stmt->fetch();

            if (!$server) {
                $this->log(null, 'auth_failed', "Invalid Serial Key: $serialKey");
                View::json(['error' => 'Invalid Serial Key'], 401);
                return false;
            }

            // Get Client IP (Handle Proxy)
            $clientIp = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '';
            // If multiple IPs in X-Forwarded-For, take the first one
            if (strpos($clientIp, ',') !== false) {
                $clientIp = trim(explode(',', $clientIp)[0]);
            }

            // Validate IP
            if ($server['ip_v4'] !== $clientIp) {
                $this->log($server['id'], 'auth_blocked', "Invalid IP Address. Expected: {$server['ip_v4']}, Got: $clientIp");
                View::json(['error' => 'Invalid IP Address'], 403);
                return false;
            }

            if ($server['status'] !== 'active') {
                $this->log($server['id'], 'auth_blocked', 'Server is inactive');
                View::json(['error' => 'Server is inactive'], 403);
                return false;
            }

            // Check if client is active
            if ($server['client_status'] !== 'active') {
                $this->log($server['id'], 'auth_blocked', 'Client is inactive');
                View::json(['error' => 'Client is inactive'], 403);
                return false;
            }

            // Bind Machine ID if first use
            if (empty($server['machine_id'])) {
                $update = $conn->prepare("UPDATE servers SET machine_id = :mid WHERE id = :id");
                $update->execute(['mid' => $machineId, 'id' => $server['id']]);
                $this->log($server['id'], 'bind_machine', "Machine ID bound: $machineId");
            }
            // Validate Machine ID
            elseif ($server['machine_id'] !== $machineId) {
                $this->log($server['id'], 'auth_blocked', "Invalid Machine ID. Expected: {$server['machine_id']}, Got: $machineId");
                View::json(['error' => 'Serial Key already bound to another machine'], 403);
                return false;
            }

            // Log Success (Optional: Log every sync might be too much, maybe only on change?
            // For now, let's log sync to show activity as requested "verificar conexões")
            $this->log($server['id'], 'sync', 'Agent connected');

            // Update Last Seen
            $updateLastSeen = $conn->prepare("UPDATE servers SET last_seen = NOW() WHERE id = :id");
            $updateLastSeen->execute(['id' => $server['id']]);

            return true;
        } catch (\Exception $e) {
            $this->log(null, 'error', 'System error: ' . $e->getMessage());
            View::json(['error' => 'Authentication error'], 500);
            return false;
        }
    }

    private function log($serverId, $action, $message)
    {
        try {
            $conn = \App\Config\Database::getInstance()->getConnection();
            $stmt = $conn->prepare("INSERT INTO api_logs (server_id, action, message, ip_address) VALUES (:sid, :act, :msg, :ip)");

            // Get Client IP (Handle Proxy)
            $clientIp = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '';
            // If multiple IPs in X-Forwarded-For, take the first one
            if (strpos($clientIp, ',') !== false) {
                $clientIp = trim(explode(',', $clientIp)[0]);
            }

            $stmt->execute([
                'sid' => $serverId,
                'act' => $action,
                'msg' => $message,
                'ip' => $clientIp
            ]);
        } catch (\Exception $e) {
            // Silent fail for logs
        }
    }
}
