<?php

namespace App\Http\Middleware;

use App\Models\Plan;
use App\Models\PlanUsage;
use App\Models\Subscription;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;

class EnforceFeatureLimits
{
    /**
     * Handle an incoming request and enforce feature limits.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next, ?string $featureName = null): Response
    {
        // Skip enforcement for guest users
        if (! Auth::check()) {
            return $next($request);
        }

        // Skip enforcement for admin users (configurable)
        if ($this->isAdminUser()) {
            return $next($request);
        }

        // Get the user's active subscription
        $subscription = $this->getActiveSubscription();
        if (! $subscription) {
            return $this->handleNoSubscription($request);
        }

        // Get the plan with features
        $plan = $subscription->plan->load(['planFeatureLimits.planFeature']);
        if (! $plan) {
            Log::error('No plan found for subscription', ['subscription_id' => $subscription->id]);

            return $next($request);
        }

        // Check if we're enforcing a specific feature
        if ($featureName) {
            return $this->enforceSpecificFeature($request, $next, $plan, $subscription, $featureName);
        }

        // General usage tracking for common features
        $this->trackGeneralUsage($request, $plan, $subscription);

        return $next($request);
    }

    /**
     * Enforce limits for a specific feature
     */
    private function enforceSpecificFeature(
        Request $request,
        Closure $next,
        Plan $plan,
        Subscription $subscription,
        string $featureName
    ): Response {
        // Check if user can use the feature
        $currentUsage = $this->getCurrentUsage($subscription->id, $featureName);
        $isOnTrial = (bool) ($subscription?->onTrial() ?? false);

        if (! $plan->canUseFeature($featureName, $currentUsage, $isOnTrial)) {
            return $this->handleFeatureLimitExceeded($request, $plan, $featureName, $currentUsage);
        }

        // Track usage if this is a usage-generating request
        if ($this->isUsageGeneratingRequest($request)) {
            $this->incrementUsage($subscription->id, $featureName);
        }

        return $next($request);
    }

    /**
     * Get user's active subscription
     */
    private function getActiveSubscription(): ?Subscription
    {
        return Auth::user()->subscriptions()
            ->whereIn('status', ['active', 'trialing'])
            ->where('ends_at', '>', now())
            ->with('plan')
            ->first();
    }

    /**
     * Handle requests from users with no subscription
     */
    private function handleNoSubscription(Request $request): Response
    {
        // Allow access to non-protected routes
        $allowedRoutes = [
            'pricing',
            'checkout.*',
            'login',
            'register',
            'home',
            'dashboard.pricing',
        ];

        foreach ($allowedRoutes as $route) {
            if ($request->routeIs($route)) {
                return $next($request);
            }
        }

        // Redirect to pricing page for other routes
        if ($request->expectsJson()) {
            return response()->json([
                'success' => false,
                'error' => 'Subscription required',
                'message' => 'Please subscribe to access this feature.',
                'redirect_url' => route('pricing'),
            ], 402);
        }

        return redirect()->route('pricing')
            ->with('error', 'Please subscribe to access this feature.');
    }

    /**
     * Handle when feature limit is exceeded
     */
    private function handleFeatureLimitExceeded(
        Request $request,
        Plan $plan,
        string $featureName,
        float $currentUsage
    ): Response {
        $feature = $plan->planFeatureLimits
            ->whereHas('planFeature', function ($query) use ($featureName) {
                $query->where('name', $featureName);
            })
            ->first();

        $featureDisplayName = $feature?->planFeature->display_name ?? $featureName;
        $limit = $feature?->limit_value ?? 'Unknown';
        $remaining = max(0, ($limit ?? 0) - $currentUsage);

        Log::info('Feature limit exceeded', [
            'user_id' => Auth::id(),
            'plan_id' => $plan->id,
            'feature' => $featureName,
            'current_usage' => $currentUsage,
            'limit' => $limit,
        ]);

        if ($request->expectsJson()) {
            return response()->json([
                'success' => false,
                'error' => 'Feature limit exceeded',
                'message' => "You have reached your limit for {$featureDisplayName}. Current usage: {$currentUsage}, Limit: {$limit}",
                'feature' => $featureName,
                'current_usage' => $currentUsage,
                'limit' => $limit,
                'remaining' => $remaining,
                'upgrade_url' => $this->getUpgradeUrl($plan),
            ], 429);
        }

        return back()->with('error', "You have reached your limit for {$featureDisplayName}.
            Current usage: {$currentUsage}, Limit: {$limit}.
            <a href='{$this->getUpgradeUrl($plan)}' class='text-blue-600 hover:underline'>Upgrade your plan</a> to increase limits.");
    }

    /**
     * Track general usage for common features
     */
    private function trackGeneralUsage(Request $request, Plan $plan, Subscription $subscription): void
    {
        // Track API calls
        if ($request->is('api/*') && $plan->hasFeature('api_access')) {
            $this->incrementUsage($subscription->id, 'api_access');
        }

        // Track email operations
        if ($this->isEmailOperation($request) && $plan->hasFeature('email_sending')) {
            $this->incrementUsage($subscription->id, 'email_sending');
        }

        // Track advanced filters usage
        if ($this->isFilterOperation($request) && $plan->hasFeature('advanced_filters')) {
            $this->incrementUsage($subscription->id, 'advanced_filters');
        }
    }

    /**
     * Check if request generates usage
     */
    private function isUsageGeneratingRequest(Request $request): bool
    {
        // POST, PUT, PATCH requests typically generate usage
        return in_array($request->method(), ['POST', 'PUT', 'PATCH']);
    }

    /**
     * Check if this is an email operation
     */
    private function isEmailOperation(Request $request): bool
    {
        return $request->is(['api/emails/*', 'emails/*']) ||
               str_contains($request->path(), 'email') ||
               $request->has('to') || $request->has('subject');
    }

    /**
     * Check if this is a filter operation
     */
    private function isFilterOperation(Request $request): bool
    {
        return $request->has('filter') ||
               $request->has('filters') ||
               str_contains($request->path(), 'filter');
    }

    /**
     * Get current usage for a feature
     */
    private function getCurrentUsage(int $subscriptionId, string $featureName): float
    {
        $usage = PlanUsage::where('subscription_id', $subscriptionId)
            ->whereHas('planFeature', function ($query) use ($featureName) {
                $query->where('name', $featureName);
            })
            ->where('period_type', 'monthly')
            ->whereMonth('created_at', now()->month)
            ->whereYear('created_at', now()->year)
            ->sum('usage_value');

        return (float) $usage;
    }

    /**
     * Increment usage for a feature
     */
    private function incrementUsage(int $subscriptionId, string $featureName): void
    {
        $subscription = Subscription::find($subscriptionId);
        $feature = $subscription->plan->planFeatureLimits
            ->whereHas('planFeature', function ($query) use ($featureName) {
                $query->where('name', $featureName);
            })
            ->first();

        if (! $feature) {
            return;
        }

        PlanUsage::updateOrCreate([
            'subscription_id' => $subscriptionId,
            'plan_id' => $subscription->plan_id,
            'user_id' => Auth::id(),
            'plan_feature_id' => $feature->plan_feature_id,
            'period_type' => $feature->limit_type === 'boolean' ? 'total' : 'monthly',
            'created_at' => now()->startOfMonth(),
        ], [
            'usage_value' => \DB::raw('usage_value + 1'),
            'updated_at' => now(),
        ]);
    }

    /**
     * Check if user is admin (bypasses limits)
     */
    private function isAdminUser(): bool
    {
        return Auth::user() && Auth::user()->level >= 10;
    }

    /**
     * Get upgrade URL for plan
     */
    private function getUpgradeUrl(Plan $currentPlan): string
    {
        $upgradePaths = $currentPlan->getUpgradePath();

        return count($upgradePaths) > 0 ? route('pricing') : route('pricing');
    }
}
