<?php

namespace App\Services\Payments\Providers;

use App\Contracts\Payments\PaymentProviderContract;
use App\Models\ActivationKey;
use App\Models\Plan;
use App\Models\Subscription;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class ActivationKeyProvider implements PaymentProviderContract
{
    protected array $config;

    public function __construct(array $config = [])
    {
        $this->config = array_merge([
            'key_prefix' => 'AK-',
            'key_length' => 32,
            'expiration_days' => null, // null means no expiration
            'success_url' => route('payment.success'),
            'cancel_url' => route('payment.cancel'),
        ], $config);
    }

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

    public function isActive(): bool
    {
        return true; // Activation keys are always available
    }

    public function createSubscription(User $user, Plan $plan, array $options = []): array
    {
        try {
            DB::beginTransaction();

            // Generate a unique activation key
            $activationKey = $this->generateUniqueActivationKey();

            // Create activation key record
            $keyRecord = ActivationKey::create([
                'user_id' => $user->id,
                'activation_key' => $activationKey,
                'price_id' => $plan->id,
                'is_activated' => false,
            ]);

            // Create subscription record
            $subscription = Subscription::create([
                'user_id' => $user->id,
                'plan_id' => $plan->id,
                'type' => 'activation_key',
                'stripe_id' => 'ak_'.$keyRecord->id.'_'.uniqid(more_entropy: true), // Use activation key ID + unique ID for compatibility
                'stripe_status' => 'pending_activation',
                'provider' => $this->getName(),
                'provider_subscription_id' => $keyRecord->id,
                'status' => 'pending_activation',
                'starts_at' => null,
                'ends_at' => null,
                'provider_data' => [
                    'activation_key' => $activationKey,
                    'key_id' => $keyRecord->id,
                    'created_at' => now()->toISOString(),
                ],
            ]);

            DB::commit();

            return [
                'provider_subscription_id' => $keyRecord->id,
                'status' => 'pending_activation',
                'activation_key' => $activationKey,
                'plan_name' => $plan->name,
                'plan_price' => $plan->price,
                'type' => 'activation_key',
                'message' => 'Activation key generated. User needs to redeem the key to activate the subscription.',
            ];

        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Activation key 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 {
            // For activation keys, we don't actually cancel since it's a one-time activation
            // We can deactivate the subscription if needed
            $subscription->update([
                'status' => 'cancelled',
                'cancelled_at' => now(),
                'cancellation_reason' => $reason,
            ]);

            return true;

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

    public function updateSubscription(Subscription $subscription, Plan $newPlan): array
    {
        try {
            // Activation keys don't support plan updates
            // User would need a new activation key for a different plan
            throw new \Exception('Activation keys do not support plan updates');
        } catch (\Exception $e) {
            Log::error('Activation key subscription update failed', [
                'subscription_id' => $subscription->id,
                'new_plan_id' => $newPlan->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    public function pauseSubscription(Subscription $subscription): bool
    {
        // Activation keys can't be paused
        return false;
    }

    public function resumeSubscription(Subscription $subscription): bool
    {
        // Activation keys can't be paused, so can't be resumed
        return false;
    }

    public function getSubscriptionDetails(string $providerSubscriptionId): array
    {
        try {
            $activationKey = ActivationKey::findOrFail($providerSubscriptionId);

            return [
                'id' => $activationKey->id,
                'activation_key' => $activationKey->activation_key,
                'user_id' => $activationKey->user_id,
                'price_id' => $activationKey->price_id,
                'is_activated' => $activationKey->is_activated,
                'created_at' => $activationKey->created_at->toISOString(),
                'updated_at' => $activationKey->updated_at->toISOString(),
            ];

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

    public function createCheckoutSession(User $user, Plan $plan, array $options = []): array
    {
        return $this->createSubscription($user, $plan, $options);
    }

    public function createCustomerPortalSession(User $user): array
    {
        return [
            'portal_url' => route('dashboard'),
            'message' => 'Activation keys are managed through your dashboard',
        ];
    }

    public function processWebhook(Request $request): array
    {
        // Activation keys don't have webhooks
        return [
            'event_type' => 'not_applicable',
            'processed' => false,
            'data' => [],
        ];
    }

    public function validateWebhook(Request $request): bool
    {
        // No webhooks to validate
        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 {
            $activationKey = ActivationKey::findOrFail($paymentMethodId);

            return [
                'id' => $activationKey->id,
                'type' => 'activation_key',
                'activation_key' => $activationKey->activation_key,
                'is_activated' => $activationKey->is_activated,
                'created_at' => $activationKey->created_at->toISOString(),
            ];

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

    public function processRefund(string $paymentId, float $amount, string $reason = ''): array
    {
        // Activation keys are not refundable
        throw new \Exception('Activation keys are not refundable');
    }

    public function getTransactionHistory(User $user, array $filters = []): array
    {
        try {
            $query = ActivationKey::where('user_id', $user->id);

            // Apply filters
            if (isset($filters['status'])) {
                if ($filters['status'] === 'activated') {
                    $query->where('is_activated', true);
                } elseif ($filters['status'] === 'unactivated') {
                    $query->where('is_activated', false);
                }
            }

            if (isset($filters['date_from'])) {
                $query->where('created_at', '>=', $filters['date_from']);
            }

            if (isset($filters['date_to'])) {
                $query->where('created_at', '<=', $filters['date_to']);
            }

            $activationKeys = $query->orderBy('created_at', 'desc')->get();

            $transactions = [];
            foreach ($activationKeys as $key) {
                $transactions[] = [
                    'id' => $key->id,
                    'activation_key' => $key->activation_key,
                    'plan_id' => $key->price_id,
                    'is_activated' => $key->is_activated,
                    'created_at' => $key->created_at->toISOString(),
                    'updated_at' => $key->updated_at->toISOString(),
                ];
            }

            return $transactions;

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

    public function calculateFees(float $amount): array
    {
        // Activation keys have no fees
        return [
            'fixed_fee' => 0,
            'percentage_fee' => 0,
            'total_fee' => 0,
            'net_amount' => $amount,
        ];
    }

    public function getSupportedCurrencies(): array
    {
        return ['USD']; // Activation keys are currency-agnostic
    }

    public function supportsRecurring(): bool
    {
        return false; // Activation keys are one-time
    }

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

    // Helper methods
    protected function generateUniqueActivationKey(): string
    {
        do {
            $key = $this->config['key_prefix'].strtoupper(Str::random($this->config['key_length']));
        } while (ActivationKey::where('activation_key', $key)->exists());

        return $key;
    }

    // Public method for redeeming activation keys
    public function redeemActivationKey(string $activationKey, User $user): array
    {
        try {
            DB::beginTransaction();

            $keyRecord = ActivationKey::where('activation_key', $activationKey)
                ->where('is_activated', false)
                ->firstOrFail();

            // Mark key as activated and assign to user
            $keyRecord->update([
                'user_id' => $user->id,
                'is_activated' => true,
            ]);

            // Find the plan associated with this activation key
            $plan = Plan::where('pricing_id', $keyRecord->price_id)->first();

            if (! $plan) {
                throw new \Exception('No plan found for activation key with pricing_id: '.$keyRecord->price_id);
            }

            // Calculate subscription end date based on plan billing cycle
            $endsAt = null;
            if ($plan->billing_cycle_days && $plan->billing_cycle_days > 0) {
                $endsAt = now()->addDays($plan->billing_cycle_days);
            }

            $subscription = Subscription::create([
                'user_id' => $user->id,
                'plan_id' => $plan->id,
                'type' => 'default',
                'stripe_id' => 'ak_'.$keyRecord->id.'_'.uniqid('', true),
                'stripe_status' => 'active',
                'provider' => $this->getName(),
                'provider_subscription_id' => $keyRecord->id,
                'status' => 'active',
                'starts_at' => now(),
                'ends_at' => $endsAt,
                'provider_data' => [
                    'activation_key' => $activationKey,
                    'key_id' => $keyRecord->id,
                    'redeemed_at' => now()->toISOString(),
                    'plan_details' => [
                        'name' => $plan->name,
                        'price' => $plan->price,
                        'billing_cycle_days' => $plan->billing_cycle_days,
                        'billing_cycle_display' => $plan->getBillingCycleDisplay(),
                        'plan_tier' => $plan->planTier ? $plan->planTier->name : null,
                        'features' => $plan->getFeaturesWithLimits(),
                    ],
                    'provider_info' => [
                        'name' => $this->getName(),
                        'version' => '1.0',
                        'processed_at' => now()->toISOString(),
                    ],
                ],
            ]);

            DB::commit();

            return [
                'success' => true,
                'subscription_id' => $subscription->id,
                'plan_name' => $plan->name,
                'message' => 'Activation key redeemed successfully',
            ];

        } catch (\Exception $e) {
            DB::rollBack();
            Log::error('Activation key redemption failed', [
                'activation_key' => $activationKey,
                'user_id' => $user->id,
                'error' => $e->getMessage(),
            ]);
            throw $e;
        }
    }

    // Additional interface methods
    public function getSubscriptionMetadata(Subscription $subscription): array
    {
        $keyDetails = $this->getSubscriptionDetails($subscription->provider_subscription_id);

        return $keyDetails + [
            'redeemed_at' => $subscription->provider_data['redeemed_at'] ?? null,
        ];
    }

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

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

            return false;
        }
    }

    public function startTrial(Subscription $subscription, int $trialDays): bool
    {
        // Activation keys don't support trials
        return false;
    }

    public function applyCoupon(Subscription $subscription, string $couponCode): array
    {
        // Activation keys don't support coupons
        throw new \Exception('Coupons not supported for activation keys');
    }

    public function removeCoupon(Subscription $subscription): bool
    {
        return false; // No coupons to remove
    }

    public function getUpcomingInvoice(Subscription $subscription): array
    {
        // Activation keys don't have invoices
        return [
            'amount_due' => 0,
            'currency' => 'USD',
            'next_payment_date' => null,
        ];
    }

    public function retryFailedPayment(Subscription $subscription): array
    {
        // No payments to retry for activation keys
        return $this->syncSubscriptionStatus($subscription);
    }

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

            return ! $details['is_activated']; // Can only modify before activation
        } catch (\Exception $e) {
            return false;
        }
    }

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

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

    public function importSubscriptionData(User $user, array $subscriptionData): array
    {
        throw new \Exception('Import to activation keys not implemented');
    }
}
