<?php

namespace App\Services\Payments;

use App\Services\Payments\Providers\ActivationKeyProvider;
use App\Services\Payments\Providers\CryptoProvider;
use App\Services\Payments\Providers\LemonSqueezyProvider;
use App\Services\Payments\Providers\OxapayProvider;
use App\Services\Payments\Providers\PolarProvider;
use App\Services\Payments\Providers\StripeProvider;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;

class PaymentConfigurationManager
{
    protected ProviderRegistry $registry;

    protected array $providerConfigs;

    public function __construct(ProviderRegistry $registry)
    {
        $this->registry = $registry;
        $this->providerConfigs = $this->loadProviderConfigurations();
    }

    /**
     * Initialize all configured payment providers
     */
    public function initializeProviders(): void
    {
        try {
            $this->registerStripeProvider();
            $this->registerLemonSqueezyProvider();
            $this->registerPolarProvider();
            $this->registerOxapayProvider();
            $this->registerCryptoProvider();
            $this->registerActivationKeyProvider();

            Log::info('Payment providers initialized', [
                'providers' => array_keys($this->registry->getAllProviders()->toArray()),
                'active_providers' => array_keys($this->registry->getActiveProviders()->toArray()),
            ]);

        } catch (\Exception $e) {
            Log::error('Failed to initialize payment providers', [
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    /**
     * Register Stripe provider if configured
     */
    protected function registerStripeProvider(): void
    {
        $config = $this->providerConfigs['stripe'] ?? [];

        if (! empty($config['secret_key'])) {
            $provider = new StripeProvider($config);
            $this->registry->register('stripe', $provider);
        }
    }

    /**
     * Register Lemon Squeezy provider if configured
     */
    protected function registerLemonSqueezyProvider(): void
    {
        $config = $this->providerConfigs['lemon_squeezy'] ?? [];

        if (! empty($config['api_key']) && ! empty($config['store_id'])) {
            $provider = new LemonSqueezyProvider($config);
            $this->registry->register('lemon_squeezy', $provider);
        }
    }

    /**
     * Register Polar provider if configured
     */
    protected function registerPolarProvider(): void
    {
        $config = $this->providerConfigs['polar'] ?? [];

        if (! empty($config['api_key'])) {
            $provider = new PolarProvider($config);
            $this->registry->register('polar', $provider);
        }
    }

    /**
     * Register OxaPay provider if configured
     */
    protected function registerOxapayProvider(): void
    {
        $config = $this->providerConfigs['oxapay'] ?? [];

        if (! empty($config['merchant_api_key'])) {
            $provider = new OxapayProvider($config);
            $this->registry->register('oxapay', $provider);
        }
    }

    /**
     * Register Crypto provider if enabled
     */
    protected function registerCryptoProvider(): void
    {
        $config = $this->providerConfigs['crypto'] ?? [];

        if ($config['enabled'] ?? false) {
            $provider = new CryptoProvider($config);
            $this->registry->register('crypto', $provider);
        }
    }

    /**
     * Register Activation Key provider (always available)
     */
    protected function registerActivationKeyProvider(): void
    {
        $config = $this->providerConfigs['activation_key'] ?? [];
        $provider = new ActivationKeyProvider($config);
        $this->registry->register('activation_key', $provider);
    }

    /**
     * Load provider configurations from config and cache
     */
    protected function loadProviderConfigurations(): array
    {
        return Cache::remember('payment_provider_configs', now()->addHour(), function () {
            return [
                'stripe' => [
                    'secret_key' => config('services.stripe.secret_key'),
                    'publishable_key' => config('services.stripe.publishable_key'),
                    'webhook_secret' => config('services.stripe.webhook_secret'),
                ],
                'lemon_squeezy' => [
                    'api_key' => config('services.lemon_squeezy.api_key'),
                    'store_id' => config('services.lemon_squeezy.store_id'),
                    'webhook_secret' => config('services.lemon_squeezy.webhook_secret'),
                ],
                'polar' => [
                    'api_key' => config('services.polar.api_key'),
                    'webhook_secret' => config('services.polar.webhook_secret'),
                ],
                'oxapay' => [
                    'merchant_api_key' => config('services.oxapay.merchant_api_key'),
                    'webhook_url' => config('services.oxapay.webhook_url'),
                    'success_url' => config('services.oxapay.success_url'),
                    'cancel_url' => config('services.oxapay.cancel_url'),
                    'sandbox' => config('services.oxapay.sandbox', false),
                ],
                'crypto' => [
                    'enabled' => config('payments.crypto.enabled', false),
                    'webhook_secret' => config('payments.crypto.webhook_secret'),
                    'confirmation_timeout_minutes' => config('payments.crypto.confirmation_timeout_minutes', 30),
                    'exchange_rate_provider' => config('payments.crypto.exchange_rate_provider', 'coingecko'),
                ],
                'activation_key' => [
                    'key_prefix' => config('payments.activation_key.prefix', 'AK-'),
                    'key_length' => config('payments.activation_key.length', 32),
                    'expiration_days' => config('payments.activation_key.expiration_days'),
                ],
            ];
        });
    }

    /**
     * Get provider configuration
     */
    public function getProviderConfig(string $provider): array
    {
        return $this->providerConfigs[$provider] ?? [];
    }

    /**
     * Update provider configuration
     */
    public function updateProviderConfig(string $provider, array $config): void
    {
        $this->providerConfigs[$provider] = array_merge(
            $this->providerConfigs[$provider] ?? [],
            $config
        );

        // Clear cache to force reload
        Cache::forget('payment_provider_configs');

        Log::info('Payment provider configuration updated', [
            'provider' => $provider,
        ]);
    }

    /**
     * Validate provider configuration
     */
    public function validateProviderConfig(string $provider, array $config): array
    {
        $errors = [];

        switch ($provider) {
            case 'stripe':
                if (empty($config['secret_key'])) {
                    $errors[] = 'Stripe secret key is required';
                }
                if (empty($config['publishable_key'])) {
                    $errors[] = 'Stripe publishable key is required';
                }
                break;

            case 'lemon_squeezy':
                if (empty($config['api_key'])) {
                    $errors[] = 'Lemon Squeezy API key is required';
                }
                if (empty($config['store_id'])) {
                    $errors[] = 'Lemon Squeezy store ID is required';
                }
                break;

            case 'polar':
                if (empty($config['api_key'])) {
                    $errors[] = 'Polar API key is required';
                }
                break;

            case 'oxapay':
                if (empty($config['merchant_api_key'])) {
                    $errors[] = 'OxaPay merchant API key is required';
                }
                break;

            case 'crypto':
                if (empty($config['webhook_secret'])) {
                    $errors[] = 'Crypto webhook secret is required';
                }
                break;

            case 'activation_key':
                // Activation keys don't require specific configuration
                break;

            default:
                $errors[] = "Unknown provider: {$provider}";
        }

        return [
            'valid' => empty($errors),
            'errors' => $errors,
        ];
    }

    /**
     * Get provider status and health information
     */
    public function getProviderStatus(): array
    {
        $status = [];
        $providers = $this->registry->getAllProviders();

        foreach ($providers as $name => $provider) {
            $status[$name] = [
                'name' => $provider->getName(),
                'active' => $provider->isActive(),
                'supports_recurring' => $provider->supportsRecurring(),
                'supports_one_time' => $provider->supportsOneTime(),
                'supported_currencies' => $provider->getSupportedCurrencies(),
                'configured' => ! empty($this->providerConfigs[$name]),
                'configuration' => $this->sanitizeConfig($this->providerConfigs[$name] ?? []),
            ];
        }

        return $status;
    }

    /**
     * Sanitize configuration for display (remove sensitive data)
     */
    protected function sanitizeConfig(array $config): array
    {
        $sensitiveKeys = ['secret_key', 'api_key', 'webhook_secret'];
        $sanitized = $config;

        foreach ($sensitiveKeys as $key) {
            if (isset($sanitized[$key]) && ! empty($sanitized[$key])) {
                $sanitized[$key] = '***'.substr($sanitized[$key], -4);
            }
        }

        return $sanitized;
    }

    /**
     * Enable/disable a provider
     */
    public function toggleProvider(string $provider, bool $enabled): bool
    {
        try {
            if ($enabled && ! $this->registry->has($provider)) {
                // Register the provider if it doesn't exist
                $this->registerProviderByName($provider);
            }

            if (! $enabled && $this->registry->has($provider)) {
                // Unregister the provider
                $this->registry->unregister($provider);
            }

            $this->updateProviderConfig($provider, ['enabled' => $enabled]);

            Log::info('Payment provider toggled', [
                'provider' => $provider,
                'enabled' => $enabled,
            ]);

            return true;

        } catch (\Exception $e) {
            Log::error('Failed to toggle payment provider', [
                'provider' => $provider,
                'enabled' => $enabled,
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    /**
     * Register a provider by name
     */
    protected function registerProviderByName(string $provider): void
    {
        switch ($provider) {
            case 'stripe':
                $this->registerStripeProvider();
                break;
            case 'lemon_squeezy':
                $this->registerLemonSqueezyProvider();
                break;
            case 'polar':
                $this->registerPolarProvider();
                break;
            case 'oxapay':
                $this->registerOxapayProvider();
                break;
            case 'crypto':
                $this->registerCryptoProvider();
                break;
            case 'activation_key':
                $this->registerActivationKeyProvider();
                break;
            default:
                throw new \InvalidArgumentException("Unknown provider: {$provider}");
        }
    }

    /**
     * Get default provider for a given plan type
     */
    public function getDefaultProvider(?string $planType = null): string
    {
        // Priority order for providers
        $priority = [
            'stripe',      // Most reliable
            'lemon_squeezy', // Good for international
            'polar',        // Developer-focused MoR
            'oxapay',       // Crypto payment gateway
            'crypto',       // For crypto payments
            'activation_key', // For manual activation
        ];

        foreach ($priority as $provider) {
            if ($this->registry->has($provider) && $this->registry->get($provider)->isActive()) {
                return $provider;
            }
        }

        // Fallback to activation key (always available)
        return 'activation_key';
    }

    /**
     * Test provider connectivity
     */
    public function testProviderConnectivity(string $provider): array
    {
        try {
            if (! $this->registry->has($provider)) {
                return [
                    'success' => false,
                    'error' => 'Provider not registered',
                ];
            }

            $providerInstance = $this->registry->get($provider);

            // Basic connectivity test - check if provider is active
            $isActive = $providerInstance->isActive();

            return [
                'success' => $isActive,
                'message' => $isActive ? 'Provider is active and ready' : 'Provider is not active',
                'details' => [
                    'name' => $providerInstance->getName(),
                    'supports_recurring' => $providerInstance->supportsRecurring(),
                    'supports_one_time' => $providerInstance->supportsOneTime(),
                ],
            ];

        } catch (\Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage(),
            ];
        }
    }

    /**
     * Refresh provider configurations
     */
    public function refreshConfigurations(): void
    {
        Cache::forget('payment_provider_configs');
        $this->providerConfigs = $this->loadProviderConfigurations();

        Log::info('Payment provider configurations refreshed');
    }
}
