<?php

namespace App\Services\Payments\Providers;

use App\Contracts\Payments\PaymentProviderContract;
use App\Models\PaymentProvider as PaymentProviderModel;
use App\Models\Plan;
use App\Models\Subscription;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class PolarProvider implements PaymentProviderContract
{
    protected array $config;

    protected bool $sandbox;

    protected string $apiBaseUrl;

    protected string $apiKey;

    protected string $webhookSecret;

    protected string $accessToken;

    // Force reload - timestamp: 2025-12-04-17-15-00

    public function __construct(array $config = [])
    {
        // DEBUG: Log that our new PolarProvider is being loaded
        Log::info('NEW PolarProvider constructor called - timestamp: 2025-12-04-17-15-00');

        // ALWAYS load configuration from PaymentProvider model to get the latest data
        $dbConfig = $this->loadConfigurationFromModel();

        // Merge with any passed config (passed config takes precedence)
        $config = array_merge($dbConfig, $config);

        Log::info('PolarProvider configuration loaded', [
            'config_keys' => array_keys($config),
            'has_api_key' => isset($config['api_key']) && ! empty($config['api_key']),
            'has_webhook_secret' => isset($config['webhook_secret']) && ! empty($config['webhook_secret']),
            'has_sandbox_api_key' => isset($config['sandbox_api_key']) && ! empty($config['sandbox_api_key']),
            'has_sandbox_webhook_secret' => isset($config['sandbox_webhook_secret']) && ! empty($config['sandbox_webhook_secret']),
            'has_access_token' => isset($config['access_token']) && ! empty($config['access_token']),
            'sandbox' => $config['sandbox'] ?? false,
        ]);

        $this->sandbox = $config['sandbox'] ?? false;
        $this->apiBaseUrl = $this->sandbox
            ? 'https://sandbox-api.polar.sh/v1'
            : 'https://api.polar.sh/v1';

        // Use sandbox credentials when sandbox mode is enabled
        if ($this->sandbox) {
            $this->apiKey = $config['sandbox_api_key'] ?? '';
            $this->webhookSecret = $config['sandbox_webhook_secret'] ?? '';
        } else {
            $this->apiKey = $config['api_key'] ?? '';
            $this->webhookSecret = $config['webhook_secret'] ?? '';
        }

        // Access token is common for both environments
        $this->accessToken = $config['access_token'] ?? '';

        Log::info('PolarProvider properties set', [
            'sandbox' => $this->sandbox,
            'api_key_empty' => empty($this->apiKey),
            'webhook_secret_empty' => empty($this->webhookSecret),
            'access_token_empty' => empty($this->accessToken),
            'using_sandbox_creds' => $this->sandbox,
            'is_active_will_be' => ! empty($this->apiKey) && ! empty($this->webhookSecret),
        ]);

        $this->config = array_merge([
            'sandbox' => $this->sandbox,
            'api_key' => $this->apiKey,
            'webhook_secret' => $this->webhookSecret,
            'success_url' => route('payment.success'),
            'cancel_url' => route('payment.cancel'),
            'webhook_url' => route('webhook.payment', 'polar'),
        ], $config);
    }

    protected function loadConfigurationFromModel(): array
    {
        try {
            $providerModel = PaymentProviderModel::where('name', 'polar')
                ->where('is_active', true)
                ->first();

            if (! $providerModel) {
                Log::error('Polar provider not found in database or not active');

                return [];
            }

            // The configuration is automatically decrypted by the encrypted:array cast
            return $providerModel->configuration ?? [];
        } catch (\Exception $e) {
            Log::error('Failed to load Polar configuration from model', [
                'error' => $e->getMessage(),
            ]);

            return [];
        }
    }

    public function getName(): string
    {
        return 'polar';
    }

    public function isActive(): bool
    {
        return ! empty($this->apiKey) && ! empty($this->webhookSecret);
    }

    public function validateCredentials(): bool
    {
        try {
            return $this->makeAuthenticatedRequest('GET', '/organizations/current')->successful();
        } catch (\Exception $e) {
            Log::error('Polar credentials validation failed', [
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    protected function makeAuthenticatedRequest(string $method, string $endpoint, array $data = []): \Illuminate\Http\Client\Response
    {
        $url = $this->apiBaseUrl.$endpoint;

        $headers = [
            'Authorization' => 'Bearer '.$this->apiKey,
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ];

        $http = Http::withHeaders($headers)
            ->timeout(30)
            ->withOptions([
                'verify' => true,
                'curl' => [
                    CURLOPT_SSL_VERIFYPEER => true,
                    CURLOPT_SSL_VERIFYHOST => 2,
                    CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2,
                ],
            ]);

        return match ($method) {
            'GET' => $http->get($url, $data),
            'POST' => $http->post($url, $data),
            'PATCH' => $http->patch($url, $data),
            'DELETE' => $http->delete($url, $data),
            default => throw new \InvalidArgumentException("Unsupported HTTP method: {$method}"),
        };
    }

    public function createSubscription(User $user, Plan $plan, array $options = []): array
    {
        try {
            Log::info('PolarProvider: createSubscription started', [
                'user_id' => $user->id,
                'plan_id' => $plan->id,
                'plan_name' => $plan->name,
            ]);

            // Get or create Polar customer
            $customer = $this->getOrCreateCustomer($user);

            Log::info('PolarProvider: Customer retrieved/created', [
                'customer_id' => $customer['id'] ?? 'null',
            ]);

            // Get or create Polar product/price
            $priceId = $this->getOrCreatePrice($plan);

            Log::info('PolarProvider: Price retrieved/created', [
                'price_id' => $priceId ?? 'null',
            ]);

            // Create checkout session
            $checkoutData = [
                'product_price_id' => $priceId,
                'customer_id' => $customer['id'],
                'success_url' => $this->config['success_url'],
                'cancel_url' => $this->config['cancel_url'],
                'customer_email' => $user->email,
                'customer_name' => $user->name,
                'metadata' => [
                    'user_id' => (string) $user->id,
                    'plan_id' => (string) $plan->id,
                    'plan_name' => $plan->name,
                    'external_id' => (string) $user->id,
                ],
            ];

            // Add discount codes if provided
            if (isset($options['discount_code'])) {
                $checkoutData['discount_code'] = $options['discount_code'];
            }

            Log::info('PolarProvider: Creating checkout session', [
                'checkout_data' => $checkoutData,
                'api_url' => $this->apiBaseUrl.'/checkouts',
            ]);

            $response = $this->makeAuthenticatedRequest('POST', '/checkouts', $checkoutData);

            Log::info('PolarProvider: Checkout response received', [
                'status' => $response->status(),
                'successful' => $response->successful(),
                'response_body' => $response->body(),
            ]);

            if (! $response->successful()) {
                $statusCode = $response->status();
                $responseBody = $response->json();

                // Log detailed error for debugging
                Log::error('Polar checkout creation failed', [
                    'status_code' => $statusCode,
                    'response' => $responseBody,
                    'user_id' => $user->id,
                    'plan_id' => $plan->id,
                ]);

                // Create user-friendly error message without exposing sensitive data
                $errorMessage = $this->sanitizePolarErrorMessage($responseBody, $statusCode);
                throw new \Exception($errorMessage);
            }

            $checkout = $response->json();

            if (! isset($checkout['id'])) {
                throw new \Exception('Invalid response from Polar API: missing checkout ID');
            }

            if (! isset($checkout['url'])) {
                throw new \Exception('Invalid response from Polar API: missing checkout URL');
            }

            // Create subscription record
            Log::info('PolarProvider: Creating subscription record', [
                'checkout_id' => $checkout['id'],
                'user_id' => $user->id,
                'plan_id' => $plan->id,
            ]);

            try {
                $subscription = Subscription::create([
                    'user_id' => $user->id,
                    'plan_id' => $plan->id,
                    'type' => 'recurring',
                    'stripe_id' => $checkout['id'], // Using stripe_id field for Polar checkout ID
                    'stripe_status' => 'pending',
                    'provider' => $this->getName(),
                    'provider_subscription_id' => $checkout['id'],
                    'status' => 'pending_payment',
                    'starts_at' => null,
                    'ends_at' => null,
                    'provider_data' => [
                        'checkout_id' => $checkout['id'],
                        'checkout_url' => $checkout['url'],
                        'customer_id' => $customer['id'],
                        'price_id' => $priceId,
                        'created_at' => now()->toISOString(),
                    ],
                ]);

                Log::info('PolarProvider: Subscription record created successfully', [
                    'subscription_id' => $subscription->id,
                ]);
            } catch (\Exception $e) {
                Log::error('PolarProvider: Failed to create subscription record', [
                    'error' => $e->getMessage(),
                    'trace' => $e->getTraceAsString(),
                ]);
                throw $e;
            }

            $result = [
                'provider_subscription_id' => $checkout['id'],
                'status' => 'pending_payment',
                'checkout_url' => $checkout['url'],
                'customer_id' => $customer['id'],
                'price_id' => $priceId,
                'type' => 'polar_checkout',
                'expires_at' => $checkout['expires_at'] ?? now()->addHours(24)->toISOString(),
            ];

            Log::info('PolarProvider: Returning successful result', [
                'result_keys' => array_keys($result),
                'checkout_url' => $result['checkout_url'],
                'provider_subscription_id' => $result['provider_subscription_id'],
            ]);

            return $result;

        } catch (\Exception $e) {
            Log::error('Polar subscription creation failed', [
                'user_id' => $user->id,
                'plan_id' => $plan->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function cancelSubscription(Subscription $subscription, string $reason = ''): bool
    {
        try {
            $polarSubscriptionId = $this->getPolarSubscriptionId($subscription);

            if (! $polarSubscriptionId) {
                // Local cancellation only
                $subscription->update([
                    'status' => 'cancelled',
                    'cancelled_at' => now(),
                    'cancellation_reason' => $reason,
                ]);

                return true;
            }

            $response = $this->makeAuthenticatedRequest('DELETE', '/subscriptions/'.$polarSubscriptionId, [
                'reason' => $reason,
            ]);

            if (! $response->successful()) {
                Log::error('Polar subscription cancellation failed: '.$response->body());
            }

            // Update local subscription
            $subscription->update([
                'status' => 'cancelled',
                'cancelled_at' => now(),
                'cancellation_reason' => $reason,
            ]);

            return true;

        } catch (\Exception $e) {
            Log::error('Polar subscription cancellation failed', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function updateSubscription(Subscription $subscription, Plan $newPlan): array
    {
        try {
            $polarSubscriptionId = $this->getPolarSubscriptionId($subscription);

            if (! $polarSubscriptionId) {
                throw new \Exception('No Polar subscription found to update');
            }

            $newPriceId = $this->getOrCreatePrice($newPlan);

            $response = $this->makeAuthenticatedRequest('PATCH', '/subscriptions/'.$polarSubscriptionId, [
                'product_price_id' => $newPriceId,
                'proration_behavior' => 'prorate',
            ]);

            if (! $response->successful()) {
                Log::error('Polar subscription update failed: '.$response->body());
            }

            $updatedSubscription = $response->json();

            // Update local subscription
            $subscription->update([
                'plan_id' => $newPlan->id,
                'provider_data' => array_merge($subscription->provider_data ?? [], [
                    'updated_at' => now()->toISOString(),
                    'polar_subscription' => $updatedSubscription,
                ]),
            ]);

            return [
                'provider_subscription_id' => $updatedSubscription['id'],
                'status' => $updatedSubscription['status'],
                'price_id' => $newPriceId,
                'updated_at' => $updatedSubscription['updated_at'],
            ];

        } catch (\Exception $e) {
            Log::error('Polar subscription update failed', [
                'subscription_id' => $subscription->id,
                'new_plan_id' => $newPlan->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function pauseSubscription(Subscription $subscription): bool
    {
        try {
            $polarSubscriptionId = $this->getPolarSubscriptionId($subscription);

            if (! $polarSubscriptionId) {
                return false;
            }

            $response = $this->makeAuthenticatedRequest('POST', '/subscriptions/'.$polarSubscriptionId.'/pause');

            if (! $response->successful()) {
                Log::error('Polar subscription pause failed: '.$response->body());
            }

            $subscription->update([
                'status' => 'paused',
                'paused_at' => now(),
            ]);

            return true;

        } catch (\Exception $e) {
            Log::error('Polar subscription pause failed', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function resumeSubscription(Subscription $subscription): bool
    {
        try {
            $polarSubscriptionId = $this->getPolarSubscriptionId($subscription);

            if (! $polarSubscriptionId) {
                return false;
            }

            $response = $this->makeAuthenticatedRequest('POST', '/subscriptions/'.$polarSubscriptionId.'/resume');

            if (! $response->successful()) {
                Log::error('Polar subscription resume failed: '.$response->body());
            }

            $subscription->update([
                'status' => 'active',
                'resumed_at' => now(),
            ]);

            return true;

        } catch (\Exception $e) {
            Log::error('Polar subscription resume failed', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function getSubscriptionDetails(string $providerSubscriptionId): array
    {
        try {
            $response = $this->makeAuthenticatedRequest('GET', '/subscriptions/'.$providerSubscriptionId);

            if (! $response->successful()) {
                Log::error('Failed to retrieve Polar subscription', [
                    'status_code' => $response->status(),
                    'response' => $response->json(),
                    'subscription_id' => $providerSubscriptionId,
                ]);
                throw new \Exception('Subscription not found. Please check your subscription details.');
            }

            $polarSubscription = $response->json();

            if (! $polarSubscription || ! isset($polarSubscription['id'])) {
                Log::error('Invalid Polar subscription response', [
                    'subscription_id' => $providerSubscriptionId,
                    'response' => $polarSubscription,
                ]);
                throw new \Exception('Invalid Polar subscription response');
            }

            return [
                'id' => $polarSubscription['id'],
                'status' => $polarSubscription['status'],
                'customer_id' => $polarSubscription['customer_id'],
                'price_id' => $polarSubscription['price_id'],
                'current_period_start' => $polarSubscription['current_period_start'],
                'current_period_end' => $polarSubscription['current_period_end'],
                'cancel_at_period_end' => $polarSubscription['cancel_at_period_end'] ?? false,
                'trial_start' => $polarSubscription['trial_start'] ?? null,
                'trial_end' => $polarSubscription['trial_end'] ?? null,
                'created_at' => $polarSubscription['created_at'],
                'updated_at' => $polarSubscription['modified_at'] ?? null,
            ];

        } catch (\Exception $e) {
            Log::error('Polar subscription details retrieval failed', [
                'subscription_id' => $providerSubscriptionId,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function createCheckoutSession(User $user, Plan $plan, array $options = []): array
    {
        Log::info('PolarProvider: createCheckoutSession called', [
            'user_id' => $user->id,
            'plan_id' => $plan->id,
            'plan_name' => $plan->name,
            'options_count' => count($options),
        ]);

        return $this->createSubscription($user, $plan, $options);
    }

    public function createCustomerPortalSession(User $user): array
    {
        try {
            $customer = $this->getOrCreateCustomer($user);

            $response = $this->makeAuthenticatedRequest('POST', '/customer-portal', [
                'customer_id' => $customer['id'],
                'return_url' => route('dashboard'),
            ]);

            if (! $response->successful()) {
                Log::error('Polar customer portal creation failed: '.$response->body());
            }

            $portal = $response->json();

            return [
                'portal_url' => $portal['url'],
                'customer_id' => $customer['id'],
            ];

        } catch (\Exception $e) {
            Log::error('Polar customer portal creation failed', [
                'user_id' => $user->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function processWebhook(Request $request): array
    {
        try {
            $payload = $request->getContent();
            $signature = $request->header('Polar-Signature');

            if (! $this->validateWebhook($request)) {
                Log::error('Invalid Polar webhook signature');
                throw new \Exception('Invalid webhook signature');
            }

            $webhookData = json_decode($payload, true);
            $eventType = $webhookData['type'] ?? 'unknown';

            $result = [
                'event_type' => $eventType,
                'processed' => false,
                'data' => [],
            ];

            switch ($eventType) {
                case 'checkout.created':
                    $result = $this->handleCheckoutCreated($webhookData);
                    break;
                case 'order.created':
                    $result = $this->handleOrderCreated($webhookData);
                    break;
                case 'order.paid':
                    $result = $this->handleOrderPaid($webhookData);
                    break;
                case 'subscription.created':
                    $result = $this->handleSubscriptionCreated($webhookData);
                    break;
                case 'subscription.active':
                    $result = $this->handleSubscriptionActive($webhookData);
                    break;
                case 'subscription.updated':
                    $result = $this->handleSubscriptionUpdated($webhookData);
                    break;
                case 'subscription.cancelled':
                    $result = $this->handleSubscriptionCancelled($webhookData);
                    break;
                case 'customer.state_changed':
                    $result = $this->handleCustomerStateChanged($webhookData);
                    break;
                default:
                    Log::info('Unhandled Polar webhook event', ['event_type' => $eventType]);
            }

            return $result;

        } catch (\Exception $e) {
            Log::error('Polar webhook processing failed', [
                'error' => $e->getMessage(),
                'payload' => $request->getContent(),
            ]);
            throw $e;
        }
    }

    public function validateWebhook(Request $request): bool
    {
        try {
            $signature = $request->header('Polar-Signature');
            $payload = $request->getContent();

            if (! $signature || ! $this->webhookSecret) {
                return false;
            }

            $expectedSignature = hash_hmac('sha256', $payload, $this->webhookSecret);

            return hash_equals($signature, $expectedSignature);

        } catch (\Exception $e) {
            Log::warning('Polar webhook validation failed', [
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    public function getConfiguration(): array
    {
        return $this->config;
    }

    public function syncSubscriptionStatus(Subscription $subscription): array
    {
        return $this->getSubscriptionDetails($subscription->provider_subscription_id);
    }

    public function getPaymentMethodDetails(string $paymentMethodId): array
    {
        try {
            // Polar doesn't have separate payment method IDs like Stripe
            // Return subscription details instead
            return $this->getSubscriptionDetails($paymentMethodId);

        } catch (\Exception $e) {
            Log::error('Polar payment method details retrieval failed', [
                'payment_method_id' => $paymentMethodId,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function processRefund(string $paymentId, float $amount, string $reason = ''): array
    {
        try {
            // Polar handles refunds through their dashboard or API
            Log::error('Polar refunds must be processed through Polar dashboard or API directly');
            throw new \Exception('Refund processing not implemented for Polar');
        } catch (\Exception $e) {
            Log::error('Polar refund processing failed', [
                'payment_id' => $paymentId,
                'amount' => $amount,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function getTransactionHistory(User $user, array $filters = []): array
    {
        try {
            $customer = $this->getOrCreateCustomer($user);

            $params = [
                'customer_id' => $customer['id'],
                'limit' => $filters['limit'] ?? 50,
            ];

            if (isset($filters['start_date'])) {
                $params['start_date'] = $filters['start_date'];
            }

            if (isset($filters['end_date'])) {
                $params['end_date'] = $filters['end_date'];
            }

            $response = $this->makeAuthenticatedRequest('GET', '/orders', $params);

            if (! $response->successful()) {
                Log::error('Failed to retrieve Polar transaction history: '.$response->body());
            }

            $polarOrders = $response->json();
            $transactions = [];

            foreach ($polarOrders['items'] ?? [] as $order) {
                $transactions[] = [
                    'id' => $order['id'],
                    'status' => $order['status'],
                    'amount' => $order['amount'] ?? 0,
                    'currency' => $order['currency'] ?? 'USD',
                    'created_at' => $order['created_at'],
                    'type' => 'order',
                ];
            }

            // Also get subscriptions
            $subscriptionResponse = $this->makeAuthenticatedRequest('GET', '/subscriptions', $params);

            if ($subscriptionResponse->successful()) {
                $polarSubscriptions = $subscriptionResponse->json();

                foreach ($polarSubscriptions['items'] ?? [] as $subscription) {
                    $transactions[] = [
                        'id' => $subscription['id'],
                        'status' => $subscription['status'],
                        'amount' => $subscription['amount'] ?? 0,
                        'currency' => $subscription['currency'] ?? 'USD',
                        'created_at' => $subscription['created_at'],
                        'type' => 'subscription',
                        'current_period_start' => $subscription['current_period_start'],
                        'current_period_end' => $subscription['current_period_end'],
                    ];
                }
            }

            // Sort by date descending
            usort($transactions, function ($a, $b) {
                return strtotime($b['created_at']) - strtotime($a['created_at']);
            });

            return $transactions;

        } catch (\Exception $e) {
            Log::error('Polar transaction history retrieval failed', [
                'user_id' => $user->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function calculateFees(float $amount): array
    {
        // Polar fees vary by plan and region (typically 5-8%)
        // Using 6% as default for calculation
        $percentageFee = $amount * 0.06;
        $totalFee = $percentageFee; // Polar typically doesn't have fixed fees

        return [
            'fixed_fee' => 0,
            'percentage_fee' => $percentageFee,
            'total_fee' => $totalFee,
            'net_amount' => $amount - $totalFee,
        ];
    }

    public function getSupportedCurrencies(): array
    {
        return ['USD']; // Polar supports USD, EUR, and other currencies, but USD is most common
    }

    public function supportsRecurring(): bool
    {
        return true;
    }

    public function supportsOneTime(): bool
    {
        return true;
    }

    // Helper methods
    protected function getOrCreateCustomer(User $user): array
    {
        // NEW 1:1 BINDING LOGIC: Use polar_cust_id for secure user binding

        // Check if user already has a Polar customer ID stored
        if ($user->polar_cust_id) {
            Log::info('User has existing Polar customer ID, using it', [
                'user_id' => $user->id,
                'polar_cust_id' => $user->polar_cust_id,
            ]);

            try {
                $response = $this->makeAuthenticatedRequest('GET', '/customers/'.$user->polar_cust_id);

                if ($response->successful()) {
                    $customer = $response->json();
                    Log::info('Successfully retrieved existing Polar customer', [
                        'user_id' => $user->id,
                        'customer_id' => $customer['id'],
                    ]);

                    return $customer;
                } else {
                    Log::warning('Stored Polar customer ID not found, will create new one', [
                        'user_id' => $user->id,
                        'polar_cust_id' => $user->polar_cust_id,
                        'status_code' => $response->status(),
                    ]);
                    // Clear the invalid ID and continue to create new customer
                    $user->update(['polar_cust_id' => null]);
                }
            } catch (\Exception $e) {
                Log::warning('Failed to retrieve stored Polar customer, will create new one', [
                    'user_id' => $user->id,
                    'polar_cust_id' => $user->polar_cust_id,
                    'error' => $e->getMessage(),
                ]);
                // Clear the invalid ID and continue to create new customer
                $user->update(['polar_cust_id' => null]);
            }
        }

        // No stored Polar customer ID, search by email to find existing customer
        Log::info('No stored Polar customer ID, searching by email', [
            'user_id' => $user->id,
            'email' => $user->email,
        ]);

        try {
            $response = $this->makeAuthenticatedRequest('GET', '/customers', [
                'email' => $user->email,
                'limit' => 10,
            ]);

            if ($response->successful()) {
                $data = $response->json();
                if (! empty($data['items'])) {
                    $customer = $data['items'][0]; // Take the first match
                    Log::info('Found existing Polar customer by email', [
                        'user_id' => $user->id,
                        'customer_id' => $customer['id'],
                        'customer_email' => $customer['email'],
                    ]);

                    // Store the Polar customer ID for future use
                    $user->update(['polar_cust_id' => $customer['id']]);

                    return $customer;
                }
            }
        } catch (\Exception $e) {
            Log::info('No existing Polar customer found by email', [
                'user_id' => $user->id,
                'error' => $e->getMessage(),
            ]);
        }

        // No existing customer found, create new one
        Log::info('Creating new Polar customer for user', [
            'user_id' => $user->id,
            'email' => $user->email,
        ]);

        // Create new customer
        $customerData = [
            'email' => $user->email,
            'name' => $user->name,
            'external_id' => (string) $user->id,
            'metadata' => [
                'user_id' => (string) $user->id,
                'source' => 'laravel_app',
            ],
        ];

        $response = $this->makeAuthenticatedRequest('POST', '/customers', $customerData);

        if (! $response->successful()) {
            $errorBody = $response->json();

            // Check if customer already exists
            if (isset($errorBody['detail']) && is_array($errorBody['detail'])) {
                foreach ($errorBody['detail'] as $error) {
                    if (isset($error['msg']) && (
                        str_contains($error['msg'], 'already exists') ||
                        str_contains($error['msg'], 'email address already exists') ||
                        str_contains($error['msg'], 'external ID already exists')
                    )) {
                        // Customer already exists, try to find again
                        Log::warning('Polar customer already exists, attempting to find again', [
                            'user_id' => $user->id,
                            'email' => $user->email,
                        ]);

                        // With the new 1:1 binding system, this shouldn't happen often
                        // But if it does, we'll handle it by searching by email again
                        Log::warning('Customer creation conflict, searching by email as fallback', [
                            'user_id' => $user->id,
                            'email' => $user->email,
                        ]);

                        // Fallback: search by email one more time
                        try {
                            $response = $this->makeAuthenticatedRequest('GET', '/customers', [
                                'email' => $user->email,
                                'limit' => 10,
                            ]);

                            if ($response->successful()) {
                                $data = $response->json();
                                if (! empty($data['items'])) {
                                    $customer = $data['items'][0];
                                    // Store the found customer ID
                                    $user->update(['polar_cust_id' => $customer['id']]);

                                    return $customer;
                                }
                            }
                        } catch (\Exception $e) {
                            Log::error('Fallback email search also failed', [
                                'user_id' => $user->id,
                                'error' => $e->getMessage(),
                            ]);
                        }

                        throw new \Exception('Unable to create or find Polar customer account. Please contact support.');
                    }
                }
            }

            Log::error('Failed to create Polar customer', [
                'status_code' => $response->status(),
                'response' => $response->json(),
                'user_id' => $user->id,
            ]);

            throw new \Exception('Failed to create customer account. Please try again or contact support.');
        }

        $customer = $response->json();

        if (! isset($customer['id'])) {
            throw new \Exception('Invalid response from Polar API: missing customer ID');
        }

        // Store the new Polar customer ID for 1:1 binding
        $user->update(['polar_cust_id' => $customer['id']]);

        Log::info('Created new Polar customer and stored ID for 1:1 binding', [
            'user_id' => $user->id,
            'customer_id' => $customer['id'],
            'external_id' => $customer['external_id'],
        ]);

        return $customer;
    }

    protected function getOrCreatePrice(Plan $plan): string
    {
        // Look for existing product by plan metadata
        try {
            $response = $this->makeAuthenticatedRequest('GET', '/products', [
                'metadata[plan_id]' => $plan->id,
                'limit' => 1,
            ]);

            if ($response->successful()) {
                $data = $response->json();
                if (! empty($data['items'])) {
                    $product = $data['items'][0];

                    // Return the first price ID from the product
                    if (! empty($product['prices'])) {
                        return $product['prices'][0]['id'];
                    }
                }
            }
        } catch (\Exception $e) {
            Log::info('No existing product found, will create new one', [
                'plan_id' => $plan->id,
            ]);
        }

        // Create new product with correct structure
        $productData = [
            'name' => $plan->name,
            'description' => $plan->description ?? 'Subscription plan',
            'recurring_interval' => 'month',
            'recurring_interval_count' => 1,
            'prices' => [
                [
                    'amount_type' => 'fixed',
                    'price_amount' => (int) ($plan->price * 100), // Convert to cents
                    'price_currency' => 'usd',
                    'recurring_interval' => 'month',
                    'recurring_interval_count' => 1,
                ],
            ],
            'metadata' => [
                'plan_id' => $plan->id,
                'plan_name' => $plan->name,
            ],
        ];

        Log::info('Creating Polar product with data', [
            'product_data' => $productData,
        ]);

        $response = $this->makeAuthenticatedRequest('POST', '/products', $productData);

        if (! $response->successful()) {
            Log::error('Failed to create Polar product', [
                'status_code' => $response->status(),
                'response' => $response->json(),
                'plan_id' => $plan->id,
            ]);

            throw new \Exception('Failed to create payment plan. Please try again or contact support.');
        }

        $product = $response->json();

        if (! isset($product['id'])) {
            throw new \Exception('Invalid response from Polar API: missing product ID');
        }

        // Polar returns the price ID in the prices array of the product
        if (! isset($product['prices'][0]['id'])) {
            throw new \Exception('Invalid response from Polar API: missing price ID in product');
        }

        Log::info('Successfully created Polar product', [
            'product_id' => $product['id'],
            'price_id' => $product['prices'][0]['id'],
        ]);

        return $product['prices'][0]['id'];
    }

    protected function getPolarSubscriptionId(Subscription $subscription): ?string
    {
        $providerData = $subscription->provider_data ?? [];

        // Try different locations where the subscription ID might be stored
        return $providerData['polar_subscription']['id'] ??
               $providerData['subscription_id'] ??
               $subscription->provider_subscription_id;
    }

    // Webhook handlers
    protected function handleCheckoutCreated(array $webhookData): array
    {
        $checkout = $webhookData['data']['object'];

        // Update local subscription with checkout ID
        Subscription::where('provider_subscription_id', $checkout['id'])->update([
            'provider_data' => array_merge(
                Subscription::where('provider_subscription_id', $checkout['id'])->first()?->provider_data ?? [],
                [
                    'checkout_id' => $checkout['id'],
                    'customer_id' => $checkout['customer_id'],
                    'polar_checkout' => $checkout,
                ]
            ),
        ]);

        return [
            'event_type' => 'checkout.created',
            'processed' => true,
            'data' => [
                'checkout_id' => $checkout['id'],
                'customer_id' => $checkout['customer_id'],
            ],
        ];
    }

    protected function handleOrderCreated(array $webhookData): array
    {
        $order = $webhookData['data']['object'];

        // Find subscription by checkout ID or customer metadata
        $subscription = Subscription::where('provider', 'polar')
            ->where(function ($query) use ($order) {
                $query->where('provider_subscription_id', $order['checkout_id'] ?? null)
                    ->orWhereHas('user', function ($q) use ($order) {
                        $q->where('email', $order['customer_email'] ?? null);
                    });
            })
            ->first();

        if ($subscription) {
            $subscription->update([
                'provider_data' => array_merge($subscription->provider_data ?? [], [
                    'order_id' => $order['id'],
                    'polar_order' => $order,
                    'order_created_at' => now()->toISOString(),
                ]),
            ]);
        }

        return [
            'event_type' => 'order.created',
            'processed' => true,
            'data' => [
                'order_id' => $order['id'],
                'checkout_id' => $order['checkout_id'] ?? null,
            ],
        ];
    }

    protected function handleOrderPaid(array $webhookData): array
    {
        $order = $webhookData['data']['object'];

        // Find and activate subscription
        $subscription = Subscription::where('provider', 'polar')
            ->where(function ($query) use ($order) {
                $query->where('provider_subscription_id', $order['checkout_id'] ?? null)
                    ->orWhereHas('user', function ($q) use ($order) {
                        $q->where('email', $order['customer_email'] ?? null);
                    });
            })
            ->first();

        if ($subscription && $subscription->status === 'pending_payment') {
            $subscription->update([
                'status' => 'active',
                'starts_at' => now(),
                'provider_data' => array_merge($subscription->provider_data ?? [], [
                    'order_paid_at' => now()->toISOString(),
                    'polar_order' => $order,
                ]),
            ]);
        }

        return [
            'event_type' => 'order.paid',
            'processed' => true,
            'data' => [
                'order_id' => $order['id'],
                'subscription_id' => $subscription?->id,
            ],
        ];
    }

    protected function handleSubscriptionCreated(array $webhookData): array
    {
        $polarSubscription = $webhookData['data']['object'];

        // Find and update local subscription
        $localSubscription = Subscription::where('provider', 'polar')
            ->where('provider_subscription_id', $polarSubscription['checkout_id'])
            ->first();

        if ($localSubscription) {
            $localSubscription->update([
                'stripe_id' => $polarSubscription['id'],
                'provider_subscription_id' => $polarSubscription['id'],
                'status' => $polarSubscription['status'],
                'starts_at' => Carbon::parse($polarSubscription['current_period_start']),
                'ends_at' => Carbon::parse($polarSubscription['current_period_end']),
                'provider_data' => array_merge($localSubscription->provider_data ?? [], [
                    'polar_subscription' => $polarSubscription,
                    'activated_at' => now()->toISOString(),
                ]),
            ]);
        }

        return [
            'event_type' => 'subscription.created',
            'processed' => true,
            'data' => [
                'subscription_id' => $polarSubscription['id'],
                'status' => $polarSubscription['status'],
            ],
        ];
    }

    protected function handleSubscriptionActive(array $webhookData): array
    {
        $polarSubscription = $webhookData['data']['object'];

        Subscription::where('provider', 'polar')
            ->where('provider_subscription_id', $polarSubscription['id'])
            ->update([
                'status' => 'active',
                'starts_at' => Carbon::parse($polarSubscription['current_period_start']),
                'ends_at' => Carbon::parse($polarSubscription['current_period_end']),
                'provider_data' => array_merge(
                    Subscription::where('provider', 'polar')
                        ->where('provider_subscription_id', $polarSubscription['id'])
                        ->first()?->provider_data ?? [],
                    [
                        'polar_subscription' => $polarSubscription,
                        'activated_at' => now()->toISOString(),
                    ]
                ),
            ]);

        return [
            'event_type' => 'subscription.active',
            'processed' => true,
            'data' => [
                'subscription_id' => $polarSubscription['id'],
                'status' => 'active',
            ],
        ];
    }

    protected function handleSubscriptionUpdated(array $webhookData): array
    {
        $polarSubscription = $webhookData['data']['object'];

        Subscription::where('provider', 'polar')
            ->where('provider_subscription_id', $polarSubscription['id'])
            ->update([
                'status' => $polarSubscription['status'],
                'provider_data' => [
                    'polar_subscription' => $polarSubscription,
                    'updated_at' => now()->toISOString(),
                ],
            ]);

        return [
            'event_type' => 'subscription.updated',
            'processed' => true,
            'data' => [
                'subscription_id' => $polarSubscription['id'],
                'status' => $polarSubscription['status'],
            ],
        ];
    }

    protected function handleSubscriptionCancelled(array $webhookData): array
    {
        $polarSubscription = $webhookData['data']['object'];

        Subscription::where('provider', 'polar')
            ->where('provider_subscription_id', $polarSubscription['id'])
            ->update([
                'status' => 'cancelled',
                'cancelled_at' => now(),
                'cancellation_reason' => 'Polar webhook cancellation',
            ]);

        return [
            'event_type' => 'subscription.cancelled',
            'processed' => true,
            'data' => [
                'subscription_id' => $polarSubscription['id'],
            ],
        ];
    }

    protected function handleCustomerStateChanged(array $webhookData): array
    {
        $customer = $webhookData['data']['object'];

        // Update all subscriptions for this customer
        Subscription::whereHas('user', function ($query) use ($customer) {
            $query->where('email', $customer['email']);
        })->where('provider', 'polar')->get()->each(function ($subscription) use ($customer) {
            $subscription->update([
                'provider_data' => array_merge($subscription->provider_data ?? [], [
                    'customer_state' => $customer['state'],
                    'customer_updated_at' => now()->toISOString(),
                ]),
            ]);
        });

        return [
            'event_type' => 'customer.state_changed',
            'processed' => true,
            'data' => [
                'customer_id' => $customer['id'],
                'state' => $customer['state'],
            ],
        ];
    }

    // Additional interface methods
    public function getSubscriptionMetadata(Subscription $subscription): array
    {
        return $subscription->provider_data['polar_subscription'] ?? [];
    }

    public function updateSubscriptionMetadata(Subscription $subscription, array $metadata): bool
    {
        try {
            $subscription->update([
                'provider_data' => array_merge($subscription->provider_data ?? [], [
                    'metadata' => $metadata,
                ]),
            ]);

            return true;
        } catch (\Exception $e) {
            Log::error('Failed to update Polar subscription metadata', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    public function startTrial(Subscription $subscription, int $trialDays): bool
    {
        // Polar handles trials through checkout creation
        // This would require creating a new checkout with trial period
        return false;
    }

    public function applyCoupon(Subscription $subscription, string $couponCode): array
    {
        try {
            $polarSubscriptionId = $this->getPolarSubscriptionId($subscription);

            if (! $polarSubscriptionId) {
                throw new \Exception('No Polar subscription found');
            }

            $response = $this->makeAuthenticatedRequest('POST', '/subscriptions/'.$polarSubscriptionId.'/discount', [
                'coupon_code' => $couponCode,
            ]);

            if (! $response->successful()) {
                Log::error('Failed to apply Polar coupon: '.$response->body());
            }

            return $response->json();

        } catch (\Exception $e) {
            Log::error('Polar coupon application failed', [
                'subscription_id' => $subscription->id,
                'coupon_code' => $couponCode,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function removeCoupon(Subscription $subscription): bool
    {
        try {
            $polarSubscriptionId = $this->getPolarSubscriptionId($subscription);

            if (! $polarSubscriptionId) {
                return false;
            }

            $response = $this->makeAuthenticatedRequest('DELETE', '/subscriptions/'.$polarSubscriptionId.'/discount');

            return $response->successful();

        } catch (\Exception $e) {
            Log::error('Polar coupon removal failed', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);

            return false;
        }
    }

    public function getUpcomingInvoice(Subscription $subscription): array
    {
        try {
            $polarSubscriptionId = $this->getPolarSubscriptionId($subscription);

            if (! $polarSubscriptionId) {
                return [
                    'amount_due' => 0,
                    'currency' => 'USD',
                    'next_payment_date' => null,
                ];
            }

            $response = $this->makeAuthenticatedRequest('GET', '/subscriptions/'.$polarSubscriptionId.'/upcoming-invoice');

            if (! $response->successful()) {
                Log::error('Failed to retrieve Polar upcoming invoice: '.$response->body());
            }

            $invoice = $response->json();

            return [
                'amount_due' => $invoice['amount_due'] / 100, // Convert from cents
                'currency' => $invoice['currency'],
                'next_payment_date' => $invoice['next_payment_date'],
            ];

        } catch (\Exception $e) {
            Log::error('Polar upcoming invoice retrieval failed', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function retryFailedPayment(Subscription $subscription): array
    {
        // Polar doesn't have explicit retry logic - payments are retried automatically
        return $this->syncSubscriptionStatus($subscription);
    }

    public function canModifySubscription(Subscription $subscription): bool
    {
        try {
            $details = $this->getSubscriptionDetails($subscription->provider_subscription_id);

            return in_array($details['status'], ['active', 'trialing']);
        } catch (\Exception $e) {
            return false;
        }
    }

    public function getCancellationTerms(Subscription $subscription): array
    {
        return [
            'immediate_cancellation' => true,
            'refund_policy' => 'no_pro_rated_refunds',
            'cancellation_effective' => 'immediately',
            'billing_cycle_proration' => false,
        ];
    }

    public function exportSubscriptionData(Subscription $subscription): array
    {
        return [
            'provider' => 'polar',
            'provider_subscription_id' => $subscription->provider_subscription_id,
            'data' => $subscription->provider_data,
        ];
    }

    public function importSubscriptionData(User $user, array $subscriptionData): array
    {
        Log::error('Import to Polar payments not implemented');
        throw new \Exception('Import subscription data not implemented for Polar');
    }

    /**
     * Sanitize Polar API error messages to prevent exposing sensitive information
     */
    private function sanitizePolarErrorMessage(array $responseBody, int $statusCode): string
    {
        // Handle specific error types with user-friendly messages
        if (isset($responseBody['error'])) {
            $errorType = $responseBody['error'];

            return match ($errorType) {
                'RequestValidationError' => $this->handleValidationError($responseBody),
                'AuthenticationError' => 'Payment service authentication failed. Please try again.',
                'InsufficientPermissions' => 'Insufficient permissions to process payment. Please contact support.',
                'ResourceNotFound' => 'Payment resource not found. Please try again.',
                'RateLimitExceeded' => 'Too many payment requests. Please wait and try again.',
                'PaymentRequired' => 'Payment required to complete this action.',
                default => 'Payment processing failed. Please try again or contact support.',
            };
        }

        // Handle validation errors in detail array
        if (isset($responseBody['detail']) && is_array($responseBody['detail'])) {
            return $this->handleValidationError($responseBody);
        }

        // Generic error based on status code
        return match ($statusCode) {
            400 => 'Invalid payment request. Please check your information and try again.',
            401 => 'Payment authentication failed. Please try again.',
            403 => 'Payment authorization failed. Please contact support.',
            404 => 'Payment service not available. Please try again.',
            429 => 'Too many payment requests. Please wait and try again.',
            500 => 'Payment service error. Please try again later.',
            502, 503, 504 => 'Payment service temporarily unavailable. Please try again later.',
            default => 'Payment processing failed. Please try again or contact support.',
        };
    }

    /**
     * Handle validation errors and extract user-friendly messages
     */
    private function handleValidationError(array $responseBody): string
    {
        if (! isset($responseBody['detail']) || ! is_array($responseBody['detail'])) {
            return 'Invalid payment information provided. Please check your details and try again.';
        }

        $errors = [];
        foreach ($responseBody['detail'] as $error) {
            if (isset($error['msg']) && isset($error['loc'])) {
                $field = $this->extractFieldName($error['loc']);
                $message = $this->sanitizeValidationMessage($error['msg'], $field);
                $errors[] = $message;
            }
        }

        if (empty($errors)) {
            return 'Invalid payment information provided. Please check your details and try again.';
        }

        return implode(' ', array_unique($errors));
    }

    /**
     * Extract field name from error location path
     */
    private function extractFieldName(array $loc): string
    {
        if (empty($loc)) {
            return 'field';
        }

        // Get the last element of the location array
        $field = end($loc);

        // Convert to user-friendly field names
        return match ($field) {
            'customer_email' => 'email address',
            'customer_name' => 'name',
            'products' => 'product selection',
            'product_id' => 'product selection',
            'product_price_id' => 'product selection',
            'success_url' => 'redirect settings',
            'cancel_url' => 'redirect settings',
            default => strtolower(str_replace('_', ' ', $field)),
        };
    }

    /**
     * Sanitize validation message to remove sensitive information
     */
    private function sanitizeValidationMessage(string $message, string $field): string
    {
        // Remove email addresses and other sensitive data from error messages
        $sanitized = preg_replace('/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/', '[email]', $message);

        // Remove domain names and URLs
        $sanitized = preg_replace('/\b[a-z0-9.-]+\.[a-z]{2,}\b/i', '[domain]', $sanitized);

        // Remove UUIDs and other identifiers
        $sanitized = preg_replace('/\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/i', '[ID]', $sanitized);

        // Convert technical terms to user-friendly language
        $sanitized = str_replace([
            'is not a valid email address',
            'does not exist',
            'Field required',
            'value_error',
            'missing',
            'type_error',
        ], [
            'is not valid',
            'is not available',
            'is required',
            'is invalid',
            'is missing',
            'is not correct',
        ], $sanitized);

        // Add field context
        return "The {$field} {$sanitized}";
    }
}
