<?php

namespace App\Http\Controllers;

use App\Models\Plan;
use App\Models\User;
use App\Services\Payments\PaymentOrchestrator;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Validation\ValidationException;

class PaymentController extends Controller
{
    public function __construct(
        private readonly PaymentOrchestrator $orchestrator
    ) {}

    /**
     * Create a checkout session for a plan
     */
    public function createCheckout(Request $request): JsonResponse
    {
        try {
            $validated = $request->validate([
                'plan_id' => 'required|exists:plans,id',
                'provider' => 'nullable|string|in:stripe,lemon_squeezy,polar,oxapay,crypto,activation_key',
                'options' => 'nullable|array',
                'is_trial' => 'nullable|boolean',
            ]);

            $user = $request->user();
            $plan = Plan::with(['planProviders', 'trialConfiguration'])->findOrFail($validated['plan_id']);
            $provider = $validated['provider'] ?? null;
            $options = $validated['options'] ?? [];
            $isTrial = $validated['is_trial'] ?? false;

            // Validate provider support
            if ($provider && ! $plan?->supportsProvider($provider)) {
                return response()->json([
                    'success' => false,
                    'error' => "Provider '{$provider}' is not supported for this plan.",
                ], 400);
            }

            // Validate trial requirements
            if ($isTrial) {
                if (! $plan?->hasTrial()) {
                    return response()->json([
                        'success' => false,
                        'error' => 'This plan does not offer trials.',
                    ], 400);
                }

                $trialConfig = $plan?->getTrialConfig();
                if ($trialConfig && $trialConfig->trial_requires_payment_method && ! $provider) {
                    return response()->json([
                        'success' => false,
                        'error' => 'Payment method is required for trial. Please specify a provider.',
                    ], 400);
                }
            }

            // Enhance options with plan-specific data
            $options = array_merge($options, [
                'is_trial' => $isTrial,
                'plan_features' => $plan?->getFeaturesWithLimits() ?? [],
                'billing_cycle' => $plan?->getBillingCycleDisplay() ?? 'Unknown',
                'plan_tier' => $plan?->planTier?->name,
            ]);

            if (! $plan) {
                return response()->json([
                    'success' => false,
                    'error' => 'Plan not found.',
                ], 404);
            }

            Log::info('PaymentController: Creating checkout session', [
                'user_id' => $user->id,
                'plan_id' => $plan->id,
                'requested_provider' => $provider,
                'is_trial' => $isTrial,
                'options_count' => count($options),
            ]);

            $result = $this->orchestrator->createCheckoutSession($user, $plan, $provider, $options);

            Log::info('PaymentController: Returning successful checkout response', [
                'result_keys' => array_keys($result),
                'has_checkout_url' => isset($result['checkout_url']),
                'checkout_url' => $result['checkout_url'] ?? 'missing',
                'provider_subscription_id' => $result['provider_subscription_id'] ?? 'missing',
            ]);

            return response()->json([
                'success' => true,
                'data' => $result,
            ]);

        } catch (ValidationException $e) {
            return response()->json([
                'success' => false,
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Create a new subscription
     */
    public function createSubscription(Request $request): JsonResponse
    {
        try {
            $validated = $request->validate([
                'plan_id' => 'required|exists:plans,id',
                'provider' => 'nullable|string|in:stripe,lemon_squeezy,polar',
                'options' => 'nullable|array',
            ]);

            $user = $request->user();
            $plan = Plan::findOrFail($validated['plan_id']);
            $provider = $validated['provider'] ?? null;
            $options = $validated['options'] ?? [];

            // Only recurring providers can create subscriptions
            if (! $plan?->monthly_billing) {
                return response()->json([
                    'success' => false,
                    'error' => 'This plan does not support recurring subscriptions. Use checkout instead.',
                ], 400);
            }

            if (! $plan) {
                return response()->json([
                    'success' => false,
                    'error' => 'Plan not found.',
                ], 404);
            }

            $result = $this->orchestrator->createSubscription($user, $plan, $provider, $options);

            return response()->json([
                'success' => true,
                'data' => $result,
            ]);

        } catch (ValidationException $e) {
            return response()->json([
                'success' => false,
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Get available payment methods for a plan
     */
    public function getPaymentMethods(Request $request): JsonResponse
    {
        try {
            $validated = $request->validate([
                'plan_id' => 'required|exists:plans,id',
            ]);

            $plan = Plan::findOrFail($validated['plan_id']);

            if (! $plan) {
                return response()->json([
                    'success' => false,
                    'error' => 'Plan not found.',
                ], 404);
            }

            $providers = $this->orchestrator->getActiveProvidersForPlan($plan);

            $methods = $providers->map(function ($provider) use ($plan) {
                return [
                    'provider' => $provider->getName(),
                    'name' => $provider->getName(),
                    'supports_recurring' => $provider->supportsRecurring(),
                    'supports_one_time' => $provider->supportsOneTime(),
                    'supported_currencies' => $provider->getSupportedCurrencies(),
                    'fees' => $provider->calculateFees($plan?->price ?? 0),
                    'active' => $provider->isActive(),
                ];
            })->values()->toArray();

            return response()->json([
                'success' => true,
                'data' => [
                    'plan' => [
                        'id' => $plan?->id,
                        'name' => $plan?->name,
                        'price' => $plan?->price,
                        'monthly_billing' => $plan?->monthly_billing,
                    ],
                    'payment_methods' => $methods,
                ],
            ]);

        } catch (ValidationException $e) {
            return response()->json([
                'success' => false,
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Get user's payment/subscription history
     */
    public function getHistory(Request $request): JsonResponse
    {
        try {
            $validated = $request->validate([
                'limit' => 'nullable|integer|min:1|max:100',
                'offset' => 'nullable|integer|min:0',
                'filters' => 'nullable|array',
            ]);

            $user = $request->user();
            $limit = $validated['limit'] ?? 20;
            $filters = $validated['filters'] ?? [];

            $history = $this->orchestrator->getTransactionHistory($user, $filters);

            // Apply pagination
            $offset = $validated['offset'] ?? 0;
            $paginatedHistory = array_slice($history, $offset, $limit);

            return response()->json([
                'success' => true,
                'data' => [
                    'transactions' => $paginatedHistory,
                    'pagination' => [
                        'total' => count($history),
                        'limit' => $limit,
                        'offset' => $offset,
                        'has_more' => $offset + $limit < count($history),
                    ],
                ],
            ]);

        } catch (ValidationException $e) {
            return response()->json([
                'success' => false,
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Handle enhanced checkout with provider selection
     */
    public function enhancedCheckout(Request $request, int $plan, string $provider)
    {
        try {
            $user = $request->user();
            $planModel = Plan::with(['planProviders', 'trialConfiguration'])->findOrFail($plan);

            // Validate provider support
            if (! $planModel->supportsProvider($provider)) {
                session()->flash('error', "Provider '{$provider}' is not supported for this plan.");

                return redirect()->route('dashboard');
            }

            // Create checkout session via orchestrator
            $result = $this->orchestrator->createCheckoutSession($user, $planModel, $provider, [
                'success_url' => route('checkout.success'),
                'cancel_url' => route('checkout.cancel'),
                'is_trial' => false,
            ]);

            Log::info('PaymentController: enhancedCheckout result', [
                'result_keys' => array_keys($result),
                'has_redirect_url' => isset($result['redirect_url']),
                'has_session_url' => isset($result['session_url']),
                'has_checkout_url' => isset($result['checkout_url']),
                'checkout_url' => $result['checkout_url'] ?? 'missing',
            ]);

            // Redirect to provider's checkout page
            if (isset($result['redirect_url'])) {
                return redirect($result['redirect_url']);
            }

            // Fallback to session-based checkout
            if (isset($result['session_url'])) {
                return redirect($result['session_url']);
            }

            // Polar checkout URL handling
            if (isset($result['checkout_url'])) {
                return redirect($result['checkout_url']);
            }

            session()->flash('error', 'Unable to create checkout session. Please try again.');

            return redirect()->route('dashboard');

        } catch (\Exception $e) {
            session()->flash('error', 'Checkout error: '.$e->getMessage());

            return redirect()->route('dashboard');
        }
    }

    /**
     * Handle trial-specific checkout flow
     */
    public function trialCheckout(Request $request, int $plan, string $provider)
    {
        try {
            $user = $request->user();
            $planModel = Plan::with(['trialConfiguration', 'planProviders'])->findOrFail($plan);

            // Validate trial availability
            if (! $planModel->hasTrial()) {
                session()->flash('error', 'This plan does not offer trials.');

                return redirect()->route('dashboard');
            }

            // Validate provider support
            if (! $planModel->supportsProvider($provider)) {
                session()->flash('error', "Provider '{$provider}' is not supported for this plan.");

                return redirect()->route('dashboard');
            }

            $trialConfig = $planModel->getTrialConfig();

            // Create trial checkout session
            $result = $this->orchestrator->createCheckoutSession($user, $planModel, $provider, [
                'success_url' => route('checkout.success'),
                'cancel_url' => route('checkout.cancel'),
                'is_trial' => true,
                'trial_duration_days' => $trialConfig?->trial_duration_days ?? 14,
                'trial_requires_payment_method' => $trialConfig?->trial_requires_payment_method ?? true,
            ]);

            Log::info('PaymentController: trialCheckout result', [
                'result_keys' => array_keys($result),
                'has_redirect_url' => isset($result['redirect_url']),
                'has_session_url' => isset($result['session_url']),
                'has_checkout_url' => isset($result['checkout_url']),
                'checkout_url' => $result['checkout_url'] ?? 'missing',
            ]);

            // Redirect to provider's checkout page
            if (isset($result['redirect_url'])) {
                return redirect($result['redirect_url']);
            }

            // Fallback to session-based checkout
            if (isset($result['session_url'])) {
                return redirect($result['session_url']);
            }

            // Polar checkout URL handling
            if (isset($result['checkout_url'])) {
                return redirect($result['checkout_url']);
            }

            session()->flash('error', 'Unable to create trial checkout session. Please try again.');

            return redirect()->route('dashboard');

        } catch (\Exception $e) {
            session()->flash('error', 'Trial checkout error: '.$e->getMessage());

            return redirect()->route('dashboard');
        }
    }

    /**
     * Handle successful payment redirect
     */
    public function success(Request $request): JsonResponse
    {
        return response()->json([
            'status' => 'success',
            'message' => 'Payment completed successfully',
        ]);
    }

    /**
     * Handle cancelled payment redirect
     */
    public function cancel(Request $request): JsonResponse
    {
        return response()->json([
            'status' => 'cancelled',
            'message' => 'Payment was cancelled',
        ]);
    }

    /**
     * Handle payment provider webhooks
     */
    public function webhook(Request $request, string $provider): JsonResponse
    {
        try {
            $result = $this->orchestrator->processWebhook($provider, $request);

            return response()->json([
                'status' => 'processed',
                'result' => $result,
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'status' => 'error',
                'message' => $e->getMessage(),
            ], 400);
        }
    }

    /**
     * Start a trial subscription
     */
    public function startTrial(Request $request): JsonResponse
    {
        try {
            $validated = $request->validate([
                'plan_id' => 'required|exists:plans,id',
                'provider' => 'required|string|in:stripe,lemon_squeezy,polar',
                'options' => 'nullable|array',
            ]);

            $user = $request->user();
            $plan = Plan::with(['trialConfiguration', 'planProviders'])->findOrFail($validated['plan_id']);
            $provider = $validated['provider'];
            $options = $validated['options'] ?? [];

            // Validate trial availability
            if (! $plan?->hasTrial()) {
                return response()->json([
                    'success' => false,
                    'error' => 'This plan does not offer trials.',
                ], 400);
            }

            // Validate provider support
            if (! $plan?->supportsProvider($provider)) {
                return response()->json([
                    'success' => false,
                    'error' => "Provider '{$provider}' is not supported for this plan.",
                ], 400);
            }

            $trialConfig = $plan?->getTrialConfig();

            // Check if user already has an active trial for this plan
            $existingTrial = $user->subscriptions()
                ->where('plan_id', $plan?->id)
                ->where('status', 'trialing')
                ->first();

            if ($existingTrial) {
                return response()->json([
                    'success' => false,
                    'error' => 'You already have an active trial for this plan.',
                ], 400);
            }

            if (! $plan) {
                return response()->json([
                    'success' => false,
                    'error' => 'Plan not found.',
                ], 404);
            }

            // Create trial subscription using checkout session with trial options
            $trialOptions = array_merge($options, [
                'is_trial' => true,
                'trial_duration_days' => $trialConfig?->trial_duration_days ?? 14,
                'trial_requires_payment_method' => $trialConfig?->trial_requires_payment_method ?? true,
            ]);

            $result = $this->orchestrator->createCheckoutSession($user, $plan, $provider, $trialOptions);

            return response()->json([
                'success' => true,
                'data' => $result,
            ]);

        } catch (ValidationException $e) {
            return response()->json([
                'success' => false,
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Get plan comparison data
     */
    public function getPlanComparison(Request $request): JsonResponse
    {
        try {
            $validated = $request->validate([
                'plan_ids' => 'required|array|min:1|max:5',
                'plan_ids.*' => 'exists:plans,id',
            ]);

            $plans = Plan::with([
                'planFeatureLimits.planFeature',
                'planProviders',
                'trialConfiguration',
                'planTier',
            ])
                ->whereIn('id', $validated['plan_ids'])
                ->active()
                ->ordered()
                ->get();

            $comparison = $plans->map(function ($plan) {
                $trialConfig = $plan?->getTrialConfig();

                return [
                    'id' => $plan?->id,
                    'name' => $plan?->name,
                    'description' => $plan?->description,
                    'price' => $plan?->price,
                    'billing_cycle' => $plan?->getBillingCycleDisplay() ?? 'Unknown',
                    'tier' => $plan?->planTier?->name,
                    'providers' => $plan?->getAllowedProviders() ?? [],
                    'features' => $plan?->getFeaturesWithLimits() ?? [],
                    'trial' => $plan?->hasTrial() ? [
                        'available' => true,
                        'duration_days' => $trialConfig?->trial_duration_days ?? 0,
                        'requires_payment_method' => $trialConfig?->trial_requires_payment_method ?? false,
                    ] : ['available' => false],
                ];
            });

            return response()->json([
                'success' => true,
                'data' => $comparison,
            ]);

        } catch (ValidationException $e) {
            return response()->json([
                'success' => false,
                'errors' => $e->errors(),
            ], 422);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Get upgrade paths for user's current subscription
     */
    public function getUpgradePaths(Request $request): JsonResponse
    {
        try {
            $user = $request->user();
            $currentSubscription = $user->subscription('default');

            if (! $currentSubscription) {
                return response()->json([
                    'success' => false,
                    'error' => 'No active subscription found.',
                ], 404);
            }

            $currentPlan = $currentSubscription->plan;
            $upgradePaths = Plan::with(['planTier', 'planFeatureLimits.planFeature'])
                ->where('id', '!=', $currentPlan->id)
                ->where(function ($query) use ($currentPlan) {
                    $query->where('price', '>', $currentPlan->price)
                        ->orWhereHas('planTier', function ($q) use ($currentPlan) {
                            $q->where('sort_order', '>', $currentPlan->planTier?->sort_order ?? 0);
                        });
                })
                ->active()
                ->ordered()
                ->get();

            $paths = $upgradePaths->map(function ($plan) use ($currentPlan) {
                return [
                    'plan' => [
                        'id' => $plan->id,
                        'name' => $plan->name,
                        'price' => $plan->price,
                        'billing_cycle' => $plan->getBillingCycleDisplay(),
                        'tier' => $plan->planTier?->name,
                    ],
                    'upgrade_benefits' => $this->getUpgradeBenefits($currentPlan, $plan),
                    'providers' => $plan->getAllowedProviders(),
                    'can_migrate' => true,
                ];
            });

            return response()->json([
                'success' => true,
                'data' => [
                    'current_plan' => [
                        'id' => $currentPlan->id,
                        'name' => $currentPlan->name,
                        'price' => $currentPlan->price,
                    ],
                    'upgrade_paths' => $paths,
                ],
            ]);

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

    /**
     * Get upgrade benefits between two plans
     */
    private function getUpgradeBenefits(Plan $currentPlan, Plan $newPlan): array
    {
        $currentFeatures = $currentPlan->getFeaturesWithLimits();
        $newFeatures = $newPlan->getFeaturesWithLimits();

        $benefits = [];

        foreach ($newFeatures as $featureData) {
            $feature = $featureData['feature'];
            $newLimit = $featureData['limit'];
            $currentLimit = collect($currentFeatures)
                ->firstWhere('feature.id', $feature->id)['limit'] ?? null;

            if (! $currentLimit || $this->isUpgradeBenefit($currentLimit, $newLimit)) {
                $benefits[] = [
                    'feature' => $feature->display_name,
                    'from' => $this->formatLimitDisplay($currentLimit),
                    'to' => $this->formatLimitDisplay($newLimit),
                    'improvement' => $this->getImprovementType($currentLimit, $newLimit),
                ];
            }
        }

        return $benefits;
    }

    /**
     * Check if a limit change is an upgrade benefit
     */
    private function isUpgradeBenefit($currentLimit, $newLimit): bool
    {
        if (! $currentLimit) {
            return true;
        }
        if (! $newLimit) {
            return false;
        }

        // Boolean upgrades
        if ($newLimit->limit_type === 'boolean') {
            return ! $currentLimit->limit_value && $newLimit->limit_value;
        }

        // Numeric upgrades
        if ($newLimit->limit_type === 'numeric') {
            return ($newLimit->limit_value ?? 0) > ($currentLimit->limit_value ?? 0);
        }

        return false;
    }

    /**
     * Format limit value for display
     */
    private function formatLimitDisplay($limit): string
    {
        if (! $limit) {
            return 'Not Available';
        }

        if ($limit->limit_type === 'boolean') {
            return $limit->limit_value ? 'Enabled' : 'Disabled';
        }

        if ($limit->limit_type === 'numeric') {
            return $limit->limit_value ? (string) $limit->limit_value : 'Unlimited';
        }

        return 'Limited';
    }

    /**
     * Get improvement type for upgrade benefit
     */
    private function getImprovementType($currentLimit, $newLimit): string
    {
        if (! $currentLimit) {
            return 'New Feature';
        }
        if ($newLimit->limit_type === 'boolean') {
            return 'Enabled';
        }
        if ($newLimit->limit_type === 'numeric') {
            return 'Increased Limit';
        }

        return 'Improved';
    }
}
