<?php

namespace AIPT\Utils;

use AIPT\Utils\Encryption;

/**
 * Centralized API Key Manager
 * 
 * This class provides a secure, centralized way to manage API keys
 * with automatic encryption/decryption and backward compatibility.
 * 
 * Features:
 * - Automatic encryption for storage
 * - Automatic decryption for usage  
 * - Backward compatibility with existing plain text keys
 * - Secure key retrieval and storage
 * - Migration support for existing installations
 * - Graceful fallback to plain text when encryption/decryption fails
 * 
 * @since 1.0.0
 */
class ApiKeyManager {
    
    /**
     * Prefix to identify encrypted data (must match Encryption class)
     */
    private const ENCRYPTED_PREFIX = 'AIPT_ENC_';
    
    /**
     * Attempt decryption with multiple methods for backward compatibility
     * 
     * @param string $encrypted_key The encrypted key to decrypt
     * @param string $provider Provider name for logging
     * @return string|null Decrypted key or null if all methods fail
     */
    private static function attempt_decryption(string $encrypted_key, string $provider): ?string {
        $decryption_methods = [
            'current' => null,  
            'legacy' => true,   
            'new' => false      
        ];
        
        foreach ($decryption_methods as $method_name => $legacy_mode) {
            try {
                $decrypted_key = Encryption::decrypt_api_key($encrypted_key, $legacy_mode);
                

                if ($decrypted_key !== $encrypted_key && !empty($decrypted_key)) {
                    return $decrypted_key;
                }
            } catch (\Exception $e) {
            }
        }
        
        return null; 
    }
    
    /**
     * Convert encrypted key to plaintext when decryption fails
     * This ensures the plugin remains functional even with encryption issues
     * 
     * @param string $provider Provider name (openai, gemini, openrouter)
     * @param string $encrypted_key The encrypted key that couldn't be decrypted
     * @return bool Success status
     */
    private static function convert_to_plaintext(string $provider, string $encrypted_key): bool {
        try {
            $option_key = "aipt_{$provider}_api_key";
            

            $plaintext_key = str_replace(self::ENCRYPTED_PREFIX, '', $encrypted_key);
            

            if (empty($plaintext_key) || strlen($plaintext_key) < 10) {
                $plaintext_key = "ENCRYPTED_FALLBACK_NEEDS_REENTRY";
            }
            

            $result = update_option($option_key, $plaintext_key);
            
            if ($result) {
            }
            
            return $result;
        } catch (\Exception $e) {
            return false;
        }
    }
    
    /**
     * Get OpenAI API key (decrypted, with plaintext fallback)
     * 
     * @return string Decrypted OpenAI API key or plaintext if decryption fails
     */
    public static function get_openai_key(): string {
        try {
            $stored_key = get_option('aipt_openai_api_key', '');
            if (empty($stored_key)) {
                return '';
            }
            

            if (!Encryption::is_encrypted($stored_key)) {
                return $stored_key;
            }
            

            $decrypted_key = self::attempt_decryption($stored_key, 'openai');
            
            if ($decrypted_key !== null) {
                return $decrypted_key;
            }
            

            self::convert_to_plaintext('openai', $stored_key);
            

            return get_option('aipt_openai_api_key', '');
            
        } catch (\Exception $e) {
            return ''; 
        }
    }
    
    /**
     * Get Gemini API key (decrypted, with plaintext fallback)
     * 
     * @return string Decrypted Gemini API key or plaintext if decryption fails
     */
    public static function get_gemini_key(): string {
        try {
            $stored_key = get_option('aipt_gemini_api_key', '');
            if (empty($stored_key)) {
                return '';
            }
            

            if (!Encryption::is_encrypted($stored_key)) {
                return $stored_key;
            }
            

            $decrypted_key = self::attempt_decryption($stored_key, 'gemini');
            
            if ($decrypted_key !== null) {
                return $decrypted_key;
            }
            

            self::convert_to_plaintext('gemini', $stored_key);
            

            return get_option('aipt_gemini_api_key', '');
            
        } catch (\Exception $e) {
            return ''; 
        }
    }
    
    /**
     * Get OpenRouter API key (decrypted, with plaintext fallback)
     * 
     * @return string Decrypted OpenRouter API key or plaintext if decryption fails
     */
    public static function get_openrouter_key(): string {
        try {
            $stored_key = get_option('aipt_openrouter_api_key', '');
            if (empty($stored_key)) {
                return '';
            }
            

            if (!Encryption::is_encrypted($stored_key)) {
                return $stored_key;
            }
            

            $decrypted_key = self::attempt_decryption($stored_key, 'openrouter');
            
            if ($decrypted_key !== null) {
                return $decrypted_key;
            }
            

            self::convert_to_plaintext('openrouter', $stored_key);
            

            return get_option('aipt_openrouter_api_key', '');
            
        } catch (\Exception $e) {
            return ''; 
        }
    }
    
    /**
     * Get Claude API key (decrypted, with plaintext fallback)
     * 
     * @return string Decrypted Claude API key or plaintext if decryption fails
     */
    public static function get_claude_key(): string {
        try {
            $stored_key = get_option('aipt_claude_api_key', '');
            if (empty($stored_key)) {
                return '';
            }
            
            if (!Encryption::is_encrypted($stored_key)) {
                return $stored_key;
            }
            
            $decrypted_key = self::attempt_decryption($stored_key, 'claude');
            
            if ($decrypted_key !== null) {
                return $decrypted_key;
            }
            
            self::convert_to_plaintext('claude', $stored_key);
            
            return get_option('aipt_claude_api_key', '');
            
        } catch (\Exception $e) {
            return '';
        }
    }
    
    /**
     * Set OpenAI API key (tries encryption, falls back to plaintext)
     * 
     * @param string $api_key Plain text API key
     * @return bool True if successfully stored (encrypted or plaintext)
     */
    public static function set_openai_key(string $api_key): bool {
        if (empty($api_key)) {
            return update_option('aipt_openai_api_key', '');
        }
        

        try {
            $encrypted_key = Encryption::encrypt_api_key($api_key);
            

            if (Encryption::is_encrypted($encrypted_key) && $encrypted_key !== $api_key) {

                $test_decrypt = Encryption::decrypt_api_key($encrypted_key);
                if ($test_decrypt === $api_key) {

                    $result = update_option('aipt_openai_api_key', $encrypted_key);
                    if ($result) {
                        return true;
                    }
                }
            }
        } catch (\Exception $e) {
        }
        

        return update_option('aipt_openai_api_key', $api_key);
    }
    
    /**
     * Set Gemini API key (tries encryption, falls back to plaintext)
     * 
     * @param string $api_key Plain text API key
     * @return bool True if successfully stored (encrypted or plaintext)
     */
    public static function set_gemini_key(string $api_key): bool {
        if (empty($api_key)) {
            return update_option('aipt_gemini_api_key', '');
        }
        

        try {
            $encrypted_key = Encryption::encrypt_api_key($api_key);
            

            if (Encryption::is_encrypted($encrypted_key) && $encrypted_key !== $api_key) {

                $test_decrypt = Encryption::decrypt_api_key($encrypted_key);
                if ($test_decrypt === $api_key) {

                    $result = update_option('aipt_gemini_api_key', $encrypted_key);
                    if ($result) {
                        return true;
                    }
                }
            }
        } catch (\Exception $e) {
        }
        

        return update_option('aipt_gemini_api_key', $api_key);
    }
    
    /**
     * Set OpenRouter API key (tries encryption, falls back to plaintext)
     * 
     * @param string $api_key Plain text API key
     * @return bool True if successfully stored (encrypted or plaintext)
     */
    public static function set_openrouter_key(string $api_key): bool {
        if (empty($api_key)) {
            return update_option('aipt_openrouter_api_key', '');
        }
        

        try {
            $encrypted_key = Encryption::encrypt_api_key($api_key);
            

            if (Encryption::is_encrypted($encrypted_key) && $encrypted_key !== $api_key) {

                $test_decrypt = Encryption::decrypt_api_key($encrypted_key);
                if ($test_decrypt === $api_key) {

                    $result = update_option('aipt_openrouter_api_key', $encrypted_key);
                    if ($result) {
                        return true;
                    }
                }
            }
        } catch (\Exception $e) {
        }
        

        return update_option('aipt_openrouter_api_key', $api_key);
    }
    
    /**
     * Set Claude API key (tries encryption, falls back to plaintext)
     * 
     * @param string $api_key Plain text API key
     * @return bool True if successfully stored (encrypted or plaintext)
     */
    public static function set_claude_key(string $api_key): bool {
        if (empty($api_key)) {
            return update_option('aipt_claude_api_key', '');
        }
        
        try {
            $encrypted_key = Encryption::encrypt_api_key($api_key);
            
            if (Encryption::is_encrypted($encrypted_key) && $encrypted_key !== $api_key) {
                $test_decrypt = Encryption::decrypt_api_key($encrypted_key);
                if ($test_decrypt === $api_key) {
                    $result = update_option('aipt_claude_api_key', $encrypted_key);
                    if ($result) {
                        return true;
                    }
                }
            }
        } catch (\Exception $e) {
        }
        
        return update_option('aipt_claude_api_key', $api_key);
    }
    
    /**
     * Get API key for current provider (decrypted)
     * 
     * @return string Decrypted API key for current provider
     */
    public static function get_current_api_key(): string {
        $api_provider = get_option('aipt_api_provider', 'openai');
        
        if ($api_provider === 'gemini') {
            return self::get_gemini_key();
        } elseif ($api_provider === 'openrouter') {
            return self::get_openrouter_key();
        } elseif ($api_provider === 'claude') {
            return self::get_claude_key();
        } else {
            return self::get_openai_key();
        }
    }
    
    /**
     * Set API key for specific provider (encrypts before storage)
     * 
     * @param string $provider API provider ('openai', 'gemini', or 'openrouter')
     * @param string $api_key Plain text API key
     * @return bool True if successfully stored
     */
    public static function set_api_key(string $provider, string $api_key): bool {
        if ($provider === 'gemini') {
            return self::set_gemini_key($api_key);
        } elseif ($provider === 'openrouter') {
            return self::set_openrouter_key($api_key);
        } elseif ($provider === 'claude') {
            return self::set_claude_key($api_key);
        } else {
            return self::set_openai_key($api_key);
        }
    }
    
    /**
     * Check if API key exists for provider
     * 
     * @param string $provider API provider ('openai', 'gemini', or 'openrouter')
     * @return bool True if API key exists and is not empty
     */
    public static function has_api_key(string $provider): bool {
        if ($provider === 'gemini') {
            return !empty(self::get_gemini_key());
        } elseif ($provider === 'openrouter') {
            return !empty(self::get_openrouter_key());
        } elseif ($provider === 'claude') {
            return !empty(self::get_claude_key());
        } else {
            return !empty(self::get_openai_key());
        }
    }
    
    /**
     * Check if any API key is configured
     * 
     * @return bool True if at least one API key is configured
     */
    public static function has_any_api_key(): bool {
        return self::has_api_key('openai') || self::has_api_key('gemini') || self::has_api_key('openrouter') || self::has_api_key('claude');
    }
    
    /**
     * Check if current provider has API key
     * 
     * @return bool True if current provider has API key
     */
    public static function has_current_api_key(): bool {
        $api_provider = get_option('aipt_api_provider', 'openai');
        return self::has_api_key($api_provider);
    }
    
    /**
     * Get raw encrypted API key (for internal use only)
     * 
     * @param string $provider API provider ('openai', 'gemini', or 'openrouter')
     * @return string Raw encrypted API key from database
     */
    public static function get_raw_api_key(string $provider): string {
        if ($provider === 'gemini') {
            return get_option('aipt_gemini_api_key', '');
        } elseif ($provider === 'openrouter') {
            return get_option('aipt_openrouter_api_key', '');
        } elseif ($provider === 'claude') {
            return get_option('aipt_claude_api_key', '');
        } else {
            return get_option('aipt_openai_api_key', '');
        }
    }
    
    /**
     * Check if API key is encrypted
     * 
     * @param string $provider API provider ('openai', 'gemini', or 'openrouter')
     * @return bool True if API key is encrypted
     */
    public static function is_api_key_encrypted(string $provider): bool {
        $raw_key = self::get_raw_api_key($provider);
        return Encryption::is_encrypted($raw_key);
    }
    
    /**
     * Get API key for display in settings (with plaintext fallback support)
     * 
     * @param string $provider API provider ('openai', 'gemini', or 'openrouter')
     * @return string API key for display (handles encryption failures gracefully)
     */
    public static function get_api_key_for_display(string $provider): string {
        $raw_key = self::get_raw_api_key($provider);
        
        if (empty($raw_key)) {
            return '';
        }
        

        if (strpos($raw_key, 'ENCRYPTED_FALLBACK_NEEDS_REENTRY') !== false) {
            return ''; 
        }
        

        if (!Encryption::is_encrypted($raw_key)) {
            return $raw_key;
        }
        

        if ($provider === 'gemini') {
            return self::get_gemini_key();
        } elseif ($provider === 'openrouter') {
            return self::get_openrouter_key(); 
        } elseif ($provider === 'claude') {
            return self::get_claude_key();
        } else {
            return self::get_openai_key();
        }
    }
    
    /**
     * Get masked API key for display purposes
     * 
     * @param string $provider API provider ('openai', 'gemini', or 'openrouter')
     * @return string Masked API key (shows only first 8 and last 4 characters)
     */
    public static function get_masked_api_key(string $provider): string {
        $api_key = '';
        
        if ($provider === 'gemini') {
            $api_key = self::get_gemini_key();
        } elseif ($provider === 'openrouter') {
            $api_key = self::get_openrouter_key();
        } elseif ($provider === 'claude') {
            $api_key = self::get_claude_key();
        } else {
            $api_key = self::get_openai_key();
        }
        
        if (empty($api_key)) {
            return '';
        }
        
        $length = strlen($api_key);
        if ($length <= 12) {
            return substr($api_key, 0, 2) . str_repeat('*', $length - 4) . substr($api_key, -2);
        }
        
        return substr($api_key, 0, 8) . str_repeat('*', $length - 12) . substr($api_key, -4);
    }
    
    /**
     * Validate API key format (basic validation)
     * 
     * @param string $provider API provider ('openai', 'gemini', or 'openrouter')
     * @param string $api_key API key to validate
     * @return bool True if format appears valid
     */
    public static function validate_api_key_format(string $provider, string $api_key): bool {
        if (empty($api_key)) {
            return false;
        }
        
        if ($provider === 'openai') {
            return preg_match('/^sk-[a-zA-Z0-9]{48}$/', $api_key) === 1;
        } elseif ($provider === 'gemini') {
            return preg_match('/^AI[a-zA-Z0-9_-]{37}$/', $api_key) === 1;
        } elseif ($provider === 'openrouter') {
            return preg_match('/^sk-or-[a-zA-Z0-9]{32,}$/', $api_key) === 1;
        } elseif ($provider === 'claude') {

            return preg_match('/^sk-ant-(api03-|admin-?)[a-zA-Z0-9_-]{40,}$/', $api_key) === 1;
        }
        
        return false;
    }
    
    /**
     * Clear API key for provider
     * 
     * @param string $provider API provider ('openai', 'gemini', or 'openrouter')
     * @return bool True if successfully cleared
     */
    public static function clear_api_key(string $provider): bool {
        if ($provider === 'gemini') {
            return update_option('aipt_gemini_api_key', '');
        } elseif ($provider === 'openrouter') {
            return update_option('aipt_openrouter_api_key', '');
        } elseif ($provider === 'claude') {
            return update_option('aipt_claude_api_key', '');
        } else {
            return update_option('aipt_openai_api_key', '');
        }
    }
    
    /**
     * Clear all API keys
     * 
     * @return bool True if all keys successfully cleared
     */
    public static function clear_all_api_keys(): bool {
        $openai_cleared = self::clear_api_key('openai');
        $gemini_cleared = self::clear_api_key('gemini');
        $openrouter_cleared = self::clear_api_key('openrouter');
        $claude_cleared = self::clear_api_key('claude');
        
        return $openai_cleared && $gemini_cleared && $openrouter_cleared && $claude_cleared;
    }
    
    /**
     * Migrate existing plain text keys to encrypted format
     * This method ensures backward compatibility during updates
     * 
     * @return bool True if migration was successful or not needed
     */
    public static function migrate_keys_if_needed(): bool {

        if (Encryption::is_migration_completed()) {
            return true;
        }
        

        return Encryption::migrate_existing_keys();
    }
    
    /**
     * Get encryption status for API keys
     * 
     * @return array Status of encryption for all providers
     */
    public static function get_encryption_status(): array {
        return [
            'openai_encrypted' => self::is_api_key_encrypted('openai'),
            'gemini_encrypted' => self::is_api_key_encrypted('gemini'),
            'openrouter_encrypted' => self::is_api_key_encrypted('openrouter'),
            'claude_encrypted' => self::is_api_key_encrypted('claude'),
            'migration_completed' => Encryption::is_migration_completed(),
            'openssl_available' => extension_loaded('openssl')
        ];
    }
} 