<?php
/**
 * API Authentication Class
 * Handles API key and token-based authentication
 */

class ApiAuth {
    private $conn;
    
    public function __construct($db_connection) {
        $this->conn = $db_connection;
    }
    
    /**
     * Authenticate API request
     * Supports API key and Bearer token authentication
     */
    public function authenticate() {
        // Check for API key in header
        $apiKey = $this->getApiKey();
        if ($apiKey) {
            return $this->authenticateApiKey($apiKey);
        }
        
        // Check for Bearer token
        $token = $this->getBearerToken();
        if ($token) {
            return $this->authenticateToken($token);
        }
        
        return [
            'success' => false,
            'message' => 'Authentication required. Provide API key or Bearer token.'
        ];
    }
    
    /**
     * Get API key from headers
     */
    private function getApiKey() {
        $headers = getallheaders();
        return $headers['X-API-Key'] ?? $headers['x-api-key'] ?? $_GET['api_key'] ?? null;
    }
    
    /**
     * Get Bearer token from Authorization header
     */
    private function getBearerToken() {
        $headers = getallheaders();
        $authHeader = $headers['Authorization'] ?? $headers['authorization'] ?? null;
        
        if ($authHeader && preg_match('/Bearer\s+(.*)$/i', $authHeader, $matches)) {
            return $matches[1];
        }
        
        return null;
    }
    
    /**
     * Authenticate using API key
     */
    private function authenticateApiKey($apiKey) {
        $sql = "SELECT u.*, r.role_name, r.role_id 
                FROM users u 
                INNER JOIN roles r ON u.role_id = r.role_id
                WHERE u.api_key = ? AND u.is_active = 1 AND u.deleted_at IS NULL";
        
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param("s", $apiKey);
        $stmt->execute();
        $result = $stmt->get_result();
        $user = $result->fetch_assoc();
        
        if ($user) {
            // Log API access
            $this->logApiAccess($user['user_id'], 'API_KEY');
            
            return [
                'success' => true,
                'user' => $user,
                'auth_method' => 'API_KEY'
            ];
        }
        
        return [
            'success' => false,
            'message' => 'Invalid API key'
        ];
    }
    
    /**
     * Authenticate using Bearer token
     */
    private function authenticateToken($token) {
        // Check if token exists and is valid
        $sql = "SELECT u.*, r.role_name, r.role_id, at.expires_at
                FROM users u 
                INNER JOIN roles r ON u.role_id = r.role_id
                INNER JOIN api_tokens at ON u.user_id = at.user_id
                WHERE at.token = ? AND at.is_active = 1 
                AND at.expires_at > NOW() 
                AND u.is_active = 1 AND u.deleted_at IS NULL";
        
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param("s", $token);
        $stmt->execute();
        $result = $stmt->get_result();
        $user = $result->fetch_assoc();
        
        if ($user) {
            // Update last used
            $updateSql = "UPDATE api_tokens SET last_used_at = NOW() WHERE token = ?";
            $updateStmt = $this->conn->prepare($updateSql);
            $updateStmt->bind_param("s", $token);
            $updateStmt->execute();
            
            // Log API access
            $this->logApiAccess($user['user_id'], 'TOKEN');
            
            return [
                'success' => true,
                'user' => $user,
                'auth_method' => 'TOKEN'
            ];
        }
        
        return [
            'success' => false,
            'message' => 'Invalid or expired token'
        ];
    }
    
    /**
     * Generate API token for user
     */
    public function generateToken($user_id, $expires_in_days = 30) {
        $token = bin2hex(random_bytes(32));
        $expires_at = date('Y-m-d H:i:s', strtotime("+$expires_in_days days"));
        
        $sql = "INSERT INTO api_tokens (user_id, token, expires_at, created_at)
                VALUES (?, ?, ?, NOW())
                ON DUPLICATE KEY UPDATE 
                token = VALUES(token),
                expires_at = VALUES(expires_at),
                created_at = NOW()";
        
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param("iss", $user_id, $token, $expires_at);
        
        if ($stmt->execute()) {
            return [
                'success' => true,
                'token' => $token,
                'expires_at' => $expires_at
            ];
        }
        
        return [
            'success' => false,
            'message' => 'Failed to generate token'
        ];
    }
    
    /**
     * Log API access
     */
    private function logApiAccess($user_id, $auth_method) {
        $sql = "INSERT INTO audit_logs (
                   event_type, event_category, user_id,
                   event_description, performed_by, ip_address
               ) VALUES (?, ?, ?, ?, ?, ?)";
        
        $event_type = 'API_ACCESS';
        $event_category = 'API';
        $description = "API access via $auth_method";
        $performed_by = 'API_SYSTEM';
        $ip_address = $_SERVER['REMOTE_ADDR'] ?? null;
        
        $stmt = $this->conn->prepare($sql);
        $stmt->bind_param("ssisss", $event_type, $event_category, $user_id, $description, $performed_by, $ip_address);
        $stmt->execute();
    }
}
