<?php

require_once __DIR__ . '/../config/config.php';
require_once __DIR__ . '/../config/database.php';
require_once __DIR__ . '/../utilities/Logger.php';

/**
 * ApiKey model for managing API keys
 */
class ApiKey {
    /**
     * Generate a new API key for a client
     * 
     * @param string $clientId Client ID
     * @param string|null $expiryDate Optional expiry date (null for no expiry)
     * @return array New API key data or error
     */
    public static function generate($clientId, $expiryDate = null) {
        try {
            $db = Database::getApiConnection();
            
            // Generate a random API key (32 characters)
            $apiKey = bin2hex(random_bytes(16)); // 16 bytes = 32 hex chars
            
            // Insert the new API key
            $stmt = $db->prepare("
                INSERT INTO api_keys (client_id, key_value, is_active, expiry_date, created_at, updated_at) 
                VALUES (?, ?, 1, ?, NOW(), NOW())
            ");
            
            $stmt->bind_param("sss", $clientId, $apiKey, $expiryDate);
            
            if (!$stmt->execute()) {
                throw new Exception("Failed to create API key: " . $stmt->error);
            }
            
            $id = $db->insert_id;
            $stmt->close();
            
            Logger::log(Logger::INFO, "New API key generated", ['client_id' => $clientId]);
            
            // Return the new API key
            return [
                'success' => true,
                'data' => [
                    'client_id' => $clientId,
                    'api_key' => $apiKey,
                    'is_active' => true,
                    'expiry_date' => $expiryDate,
                    'created_at' => date('c')
                ]
            ];
            
        } catch (Exception $e) {
            Logger::log(Logger::ERROR, "API key generation error: " . $e->getMessage());
            return [
                'success' => false,
                'error' => [
                    'message' => 'Failed to generate API key',
                    'code' => 'SERVER_ERROR'
                ]
            ];
        }
    }
    
    /**
     * Validate an API key
     * 
     * @param string $apiKey API key to validate
     * @return array Validation result with client_id if valid
     */
    public static function validate($apiKey) {
        try {
            $db = Database::getApiConnection();
            
            // Check if API key exists and is active
            $stmt = $db->prepare("
                SELECT client_id, expiry_date 
                FROM api_keys 
                WHERE key_value = ? AND is_active = 1
            ");
            
            $stmt->bind_param("s", $apiKey);
            $stmt->execute();
            $result = $stmt->get_result();
            
            if ($result->num_rows == 0) {
                Logger::log(Logger::WARNING, "Invalid API key used", ['key' => self::maskApiKey($apiKey)]);
                return ['valid' => false];
            }
            
            $row = $result->fetch_assoc();
            $stmt->close();
            
            // Check if API key has expired
            if ($row['expiry_date'] && strtotime($row['expiry_date']) < time()) {
                Logger::log(Logger::WARNING, "Expired API key used", [
                    'client_id' => $row['client_id'],
                    'key' => self::maskApiKey($apiKey),
                    'expiry_date' => $row['expiry_date']
                ]);
                return ['valid' => false];
            }
            
            Logger::log(Logger::DEBUG, "API key validated successfully", ['client_id' => $row['client_id']]);
            
            return [
                'valid' => true,
                'client_id' => $row['client_id']
            ];
            
        } catch (Exception $e) {
            Logger::log(Logger::ERROR, "API key validation error: " . $e->getMessage());
            return ['valid' => false];
        }
    }
    
    /**
     * Deactivate an API key
     * 
     * @param string $apiKey API key to deactivate
     * @return array Result of deactivation
     */
    public static function deactivate($apiKey) {
        try {
            $db = Database::getApiConnection();
            
            // Deactivate the API key
            $stmt = $db->prepare("
                UPDATE api_keys 
                SET is_active = 0, updated_at = NOW()
                WHERE key_value = ?
            ");
            
            $stmt->bind_param("s", $apiKey);
            
            if (!$stmt->execute()) {
                throw new Exception("Failed to deactivate API key: " . $stmt->error);
            }
            
            $affected = $stmt->affected_rows;
            $stmt->close();
            
            if ($affected == 0) {
                return [
                    'success' => false,
                    'error' => [
                        'message' => 'API key not found',
                        'code' => 'NOT_FOUND'
                    ]
                ];
            }
            
            Logger::log(Logger::INFO, "API key deactivated", ['key' => self::maskApiKey($apiKey)]);
            
            return [
                'success' => true,
                'data' => [
                    'message' => 'API key deactivated successfully'
                ]
            ];
            
        } catch (Exception $e) {
            Logger::log(Logger::ERROR, "API key deactivation error: " . $e->getMessage());
            return [
                'success' => false,
                'error' => [
                    'message' => 'Failed to deactivate API key',
                    'code' => 'SERVER_ERROR'
                ]
            ];
        }
    }
    
    /**
     * Get all API keys for a client
     * 
     * @param string $clientId Client ID
     * @return array List of API keys
     */
    public static function getAllForClient($clientId) {
        try {
            $db = Database::getApiConnection();
            
            // Get all API keys for this client
            $stmt = $db->prepare("
                SELECT id, key_value, is_active, expiry_date, created_at, updated_at
                FROM api_keys
                WHERE client_id = ?
                ORDER BY created_at DESC
            ");
            
            $stmt->bind_param("s", $clientId);
            $stmt->execute();
            $result = $stmt->get_result();
            
            $keys = [];
            while ($row = $result->fetch_assoc()) {
                // Only show the first and last 4 characters of the API key
                $maskedKey = substr($row['key_value'], 0, 4) . '...' . substr($row['key_value'], -4);
                
                $keys[] = [
                    'id' => $row['id'],
                    'key' => $maskedKey,
                    'is_active' => (bool)$row['is_active'],
                    'expiry_date' => $row['expiry_date'] ? date('c', strtotime($row['expiry_date'])) : null,
                    'created_at' => date('c', strtotime($row['created_at'])),
                    'updated_at' => date('c', strtotime($row['updated_at']))
                ];
            }
            
            $stmt->close();
            
            return [
                'success' => true,
                'data' => $keys
            ];
            
        } catch (Exception $e) {
            Logger::log(Logger::ERROR, "Get API keys error: " . $e->getMessage());
            return [
                'success' => false,
                'error' => [
                    'message' => 'Failed to retrieve API keys',
                    'code' => 'SERVER_ERROR'
                ]
            ];
        }
    }
    
    /**
     * Rotate an API key (create a new one and deactivate the old one)
     * 
     * @param string $oldApiKey Old API key to replace
     * @param string|null $expiryDate Optional expiry date for new key
     * @return array New API key data or error
     */
    public static function rotate($oldApiKey, $expiryDate = null) {
        try {
            $db = Database::getApiConnection();
            
            // First, get the client ID for this API key
            $stmt = $db->prepare("
                SELECT client_id 
                FROM api_keys 
                WHERE key_value = ?
            ");
            
            $stmt->bind_param("s", $oldApiKey);
            $stmt->execute();
            $result = $stmt->get_result();
            
            if ($result->num_rows == 0) {
                return [
                    'success' => false,
                    'error' => [
                        'message' => 'API key not found',
                        'code' => 'NOT_FOUND'
                    ]
                ];
            }
            
            $row = $result->fetch_assoc();
            $clientId = $row['client_id'];
            $stmt->close();
            
            // Begin transaction
            $db->begin_transaction();
            
            try {
                // Deactivate the old key
                $deactivateStmt = $db->prepare("
                    UPDATE api_keys 
                    SET is_active = 0, updated_at = NOW()
                    WHERE key_value = ?
                ");
                
                $deactivateStmt->bind_param("s", $oldApiKey);
                $deactivateStmt->execute();
                $deactivateStmt->close();
                
                // Generate a new key
                $newApiKey = bin2hex(random_bytes(16));
                
                $createStmt = $db->prepare("
                    INSERT INTO api_keys (client_id, key_value, is_active, expiry_date, created_at, updated_at) 
                    VALUES (?, ?, 1, ?, NOW(), NOW())
                ");
                
                $createStmt->bind_param("sss", $clientId, $newApiKey, $expiryDate);
                $createStmt->execute();
                $createStmt->close();
                
                $db->commit();
                
                Logger::log(Logger::INFO, "API key rotated", [
                    'client_id' => $clientId,
                    'old_key' => self::maskApiKey($oldApiKey)
                ]);
                
                return [
                    'success' => true,
                    'data' => [
                        'client_id' => $clientId,
                        'api_key' => $newApiKey,
                        'is_active' => true,
                        'expiry_date' => $expiryDate,
                        'created_at' => date('c')
                    ]
                ];
                
            } catch (Exception $e) {
                $db->rollback();
                throw $e;
            }
            
        } catch (Exception $e) {
            Logger::log(Logger::ERROR, "API key rotation error: " . $e->getMessage());
            return [
                'success' => false,
                'error' => [
                    'message' => 'Failed to rotate API key',
                    'code' => 'SERVER_ERROR'
                ]
            ];
        }
    }
    
    /**
     * Mask API key for logging (show only first 4 and last 4 characters)
     * 
     * @param string $apiKey Full API key
     * @return string Masked API key
     */
    private static function maskApiKey($apiKey) {
        $length = strlen($apiKey);
        if ($length <= 8) {
            return str_repeat('*', $length);
        }
        
        return substr($apiKey, 0, 4) . str_repeat('*', $length - 8) . substr($apiKey, -4);
    }
} 