<?php

namespace App\Http\Controllers;

use App\Models\Coupon;
use App\Models\Subscription;
use App\NotifyMe;
use App\Services\Payments\PaymentOrchestrator;
use Exception;
use Illuminate\Contracts\Routing\ResponseFactory;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Log;

class WebhookController extends Controller
{
    use NotifyMe;

    public function __construct(
        private PaymentOrchestrator $orchestrator
    ) {}

    /**
     * Unified webhook handler for all payment providers
     */
    public function handle(Request $request, string $provider): ResponseFactory|Response
    {
        try {
            Log::info("Processing {$provider} webhook", [
                'provider' => $provider,
                'headers' => $request->headers->all(),
            ]);

            $result = $this->orchestrator->processWebhook($provider, $request);

            // Process Phase 4 specific events
            $this->processPhase4Events($provider, $result);

            // Send notification for successful payments
            if ($this->isSuccessfulPayment($result)) {
                $this->sendPaymentNotification($provider, $result);
            }

            // Send notifications for Phase 4 events
            $this->sendPhase4Notifications($provider, $result);

            return response('OK', 200);

        } catch (Exception $e) {
            Log::error("{$provider} webhook processing error", [
                'provider' => $provider,
                'error' => $e->getMessage(),
                'request_data' => $request->getContent(),
            ]);

            $this->sendErrorNotification($provider, $e);

            return response('Processing error', 400);
        }
    }

    /**
     * Legacy Oxapay webhook handler (for backward compatibility)
     */
    public function oxapay(Request $request): ResponseFactory|Response
    {
        return $this->handle($request, 'oxapay');
    }

    /**
     * Stripe webhook handler
     */
    public function stripe(Request $request): ResponseFactory|Response
    {
        return $this->handle($request, 'stripe');
    }

    /**
     * Lemon Squeezy webhook handler
     */
    public function lemonSqueezy(Request $request): ResponseFactory|Response
    {
        return $this->handle($request, 'lemon_squeezy');
    }

    /**
     * Polar webhook handler
     */
    public function polar(Request $request): ResponseFactory|Response
    {
        return $this->handle($request, 'polar');
    }

    /**
     * Crypto webhook handler
     */
    public function crypto(Request $request): ResponseFactory|Response
    {
        return $this->handle($request, 'crypto');
    }

    /**
     * Check if webhook result indicates a successful payment
     */
    protected function isSuccessfulPayment(array $result): bool
    {
        if (! ($result['success'] ?? false)) {
            return false;
        }

        $eventType = $result['event_type'] ?? '';
        $status = $result['status'] ?? '';

        // Check for successful payment events
        $successfulEvents = [
            'payment.succeeded',
            'invoice.payment_succeeded',
            'checkout.session.completed',
            'subscription.created',
            'subscription.updated',
            'customer.subscription.created',
            'charge.succeeded',
            'payment_intent.succeeded',
            'invoicepaid',
            'Paid', // OxaPay status
        ];

        return in_array($eventType, $successfulEvents) ||
               in_array($status, ['paid', 'succeeded', 'completed', 'active']);
    }

    /**
     * Send notification for successful payment
     */
    protected function sendPaymentNotification(string $provider, array $result): void
    {
        $eventType = $result['event_type'] ?? $result['status'] ?? 'unknown';
        $subscriptionId = $result['subscription_id'] ?? null;
        $amount = $result['amount'] ?? 'Unknown';
        $currency = $result['currency'] ?? 'Unknown';
        $email = $result['email'] ?? 'Unknown';

        $message = "✅ {$this->getProviderDisplayName($provider)} Payment Success\n".
                   "Event: {$eventType}\n".
                   "Amount: {$amount} {$currency}\n".
                   ($subscriptionId ? "Subscription ID: {$subscriptionId}\n" : '').
                   ($email !== 'Unknown' ? "Email: {$email}\n" : '').
                   'Time: '.now()->toDateTimeString();

        $this->sendTelegramNotification($message);
    }

    /**
     * Send error notification
     */
    protected function sendErrorNotification(string $provider, Exception $e): void
    {
        $message = "❌ {$this->getProviderDisplayName($provider)} Webhook Error\n".
                   "Error: {$e->getMessage()}\n".
                   'Time: '.now()->toDateTimeString();

        $this->sendTelegramNotification($message);
    }

    /**
     * Process Phase 4 specific events
     */
    protected function processPhase4Events(string $provider, array $result): void
    {
        $eventType = $result['event_type'] ?? '';
        $subscriptionId = $result['subscription_id'] ?? null;

        if (! $subscriptionId) {
            return;
        }

        $subscription = Subscription::find($subscriptionId);
        if (! $subscription) {
            Log::warning('Subscription not found for Phase 4 processing', [
                'subscription_id' => $subscriptionId,
                'provider' => $provider,
            ]);

            return;
        }

        // Handle coupon usage events
        if ($this->isCouponUsageEvent($result)) {
            $this->processCouponUsage($subscription, $result);
        }

        // Handle trial events
        if ($this->isTrialEvent($result)) {
            $this->processTrialEvent($subscription, $result);
        }

        // Handle subscription change events
        if ($this->isSubscriptionChangeEvent($result)) {
            $this->processSubscriptionChangeEvent($subscription, $result);
        }

        // Handle migration events
        if ($this->isMigrationEvent($result)) {
            $this->processMigrationEvent($subscription, $result);
        }
    }

    /**
     * Process coupon usage
     */
    protected function processCouponUsage(Subscription $subscription, array $result): void
    {
        try {
            $couponCode = $result['coupon_code'] ?? null;
            $discountAmount = $result['discount_amount'] ?? 0;

            if (! $couponCode) {
                return;
            }

            $coupon = Coupon::where('code', $couponCode)->first();
            if (! $coupon) {
                Log::warning('Coupon not found', ['coupon_code' => $couponCode]);

                return;
            }

            // Apply coupon to subscription if not already applied
            $existingUsage = $subscription->couponUsages()
                ->where('coupon_id', $coupon->id)
                ->first();

            if (! $existingUsage) {
                $subscription->applyCoupon($coupon, $discountAmount);
                Log::info('Coupon applied via webhook', [
                    'subscription_id' => $subscription->id,
                    'coupon_id' => $coupon->id,
                    'discount_amount' => $discountAmount,
                ]);
            }

        } catch (Exception $e) {
            Log::error('Failed to process coupon usage', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Process trial events
     */
    protected function processTrialEvent(Subscription $subscription, array $result): void
    {
        try {
            $eventType = $result['event_type'] ?? '';
            $newTrialEnd = $result['trial_ends_at'] ?? null;

            if (! $newTrialEnd) {
                return;
            }

            switch ($eventType) {
                case 'trial.will_end':
                case 'trial.ending':
                    // Send reminder notification
                    $this->sendTrialEndingNotification($subscription);
                    break;

                case 'trial.extended':
                    // Record trial extension
                    $daysExtended = $result['trial_extension_days'] ?? 7;
                    $reason = $result['extension_reason'] ?? 'Extended by provider';
                    $subscription->extendTrial($daysExtended, $reason, 'automatic');
                    break;

                case 'trial.ended':
                    // Record trial completion
                    $this->recordTrialCompletion($subscription, $result);
                    break;
            }

        } catch (Exception $e) {
            Log::error('Failed to process trial event', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Process subscription change events
     */
    protected function processSubscriptionChangeEvent(Subscription $subscription, array $result): void
    {
        try {
            $eventType = $result['event_type'] ?? '';
            $oldPlanId = $result['old_plan_id'] ?? null;
            $newPlanId = $result['new_plan_id'] ?? null;

            switch ($eventType) {
                case 'plan.changed':
                case 'subscription.updated':
                    if ($oldPlanId && $newPlanId) {
                        $changeType = $this->determinePlanChangeType($oldPlanId, $newPlanId);
                        $this->orchestrator->recordSubscriptionChange(
                            $subscription,
                            $changeType,
                            "Plan changed from {$oldPlanId} to {$newPlanId}",
                            ['plan_id' => $oldPlanId],
                            ['plan_id' => $newPlanId],
                            'Plan change via webhook'
                        );
                    }
                    break;

                case 'subscription.paused':
                    $this->orchestrator->recordSubscriptionChange(
                        $subscription,
                        'pause',
                        'Subscription paused via webhook',
                        null,
                        ['status' => 'paused'],
                        'Paused by provider'
                    );
                    break;

                case 'subscription.resumed':
                    $this->orchestrator->recordSubscriptionChange(
                        $subscription,
                        'resume',
                        'Subscription resumed via webhook',
                        ['status' => 'paused'],
                        ['status' => 'active'],
                        'Resumed by provider'
                    );
                    break;

                case 'subscription.cancelled':
                    $reason = $result['cancellation_reason'] ?? 'Cancelled by provider';
                    $this->orchestrator->recordSubscriptionChange(
                        $subscription,
                        'cancel',
                        'Subscription cancelled via webhook',
                        null,
                        ['status' => 'cancelled', 'reason' => $reason],
                        $reason
                    );
                    break;
            }

        } catch (Exception $e) {
            Log::error('Failed to process subscription change event', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Process migration events
     */
    protected function processMigrationEvent(Subscription $subscription, array $result): void
    {
        try {
            $targetProvider = $result['target_provider'] ?? null;
            $migrationBatchId = $result['migration_batch_id'] ?? null;

            if (! $targetProvider || ! $migrationBatchId) {
                return;
            }

            $subscription->update([
                'migration_batch_id' => $migrationBatchId,
                'is_migrated' => true,
                'legacy_data' => array_merge($subscription->legacy_data ?? [], [
                    'migration_source' => $result['source_provider'] ?? $subscription->provider,
                    'migration_date' => now()->toDateTimeString(),
                    'migration_reason' => $result['migration_reason'] ?? 'Provider migration',
                ]),
            ]);

            Log::info('Subscription migration recorded', [
                'subscription_id' => $subscription->id,
                'migration_batch_id' => $migrationBatchId,
                'target_provider' => $targetProvider,
            ]);

        } catch (Exception $e) {
            Log::error('Failed to process migration event', [
                'subscription_id' => $subscription->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Send Phase 4 specific notifications
     */
    protected function sendPhase4Notifications(string $provider, array $result): void
    {
        $eventType = $result['event_type'] ?? '';

        switch ($eventType) {
            case 'coupon.applied':
                $this->sendCouponAppliedNotification($provider, $result);
                break;

            case 'trial.ending':
                $this->sendTrialEndingNotification($result);
                break;

            case 'trial.extended':
                $this->sendTrialExtendedNotification($provider, $result);
                break;

            case 'plan.changed':
                $this->sendPlanChangedNotification($provider, $result);
                break;

            case 'subscription.migrated':
                $this->sendMigrationNotification($provider, $result);
                break;
        }
    }

    /**
     * Send coupon applied notification
     */
    protected function sendCouponAppliedNotification(string $provider, array $result): void
    {
        $couponCode = $result['coupon_code'] ?? 'Unknown';
        $discountAmount = $result['discount_amount'] ?? 0;
        $email = $result['email'] ?? 'Unknown';

        $message = "🎫 Coupon Applied\n".
                   "Provider: {$this->getProviderDisplayName($provider)}\n".
                   "Coupon: {$couponCode}\n".
                   "Discount: {$discountAmount}\n".
                   "Email: {$email}\n".
                   'Time: '.now()->toDateTimeString();

        $this->sendTelegramNotification($message);
    }

    /**
     * Send trial ending notification
     */
    protected function sendTrialEndingNotification($subscriptionOrResult): void
    {
        if ($subscriptionOrResult instanceof Subscription) {
            $subscription = $subscriptionOrResult;
            $email = $subscription->user?->email ?? 'Unknown';
            $trialEndsAt = $subscription->trial_ends_at?->toDateTimeString() ?? 'Unknown';
        } else {
            $email = $subscriptionOrResult['email'] ?? 'Unknown';
            $trialEndsAt = $subscriptionOrResult['trial_ends_at'] ?? 'Unknown';
        }

        $message = "⏰ Trial Ending Soon\n".
                   "Email: {$email}\n".
                   "Trial ends: {$trialEndsAt}\n".
                   'Time: '.now()->toDateTimeString();

        $this->sendTelegramNotification($message);
    }

    /**
     * Send trial extended notification
     */
    protected function sendTrialExtendedNotification(string $provider, array $result): void
    {
        $daysExtended = $result['trial_extension_days'] ?? 0;
        $newTrialEnd = $result['new_trial_ends_at'] ?? 'Unknown';
        $reason = $result['extension_reason'] ?? 'Extended';

        $message = "✅ Trial Extended\n".
                   "Provider: {$this->getProviderDisplayName($provider)}\n".
                   "Days extended: {$daysExtended}\n".
                   "New trial end: {$newTrialEnd}\n".
                   "Reason: {$reason}\n".
                   'Time: '.now()->toDateTimeString();

        $this->sendTelegramNotification($message);
    }

    /**
     * Send plan changed notification
     */
    protected function sendPlanChangedNotification(string $provider, array $result): void
    {
        $oldPlan = $result['old_plan_name'] ?? 'Unknown';
        $newPlan = $result['new_plan_name'] ?? 'Unknown';
        $email = $result['email'] ?? 'Unknown';

        $message = "🔄 Plan Changed\n".
                   "Provider: {$this->getProviderDisplayName($provider)}\n".
                   "Email: {$email}\n".
                   "Old plan: {$oldPlan}\n".
                   "New plan: {$newPlan}\n".
                   'Time: '.now()->toDateTimeString();

        $this->sendTelegramNotification($message);
    }

    /**
     * Send migration notification
     */
    protected function sendMigrationNotification(string $provider, array $result): void
    {
        $sourceProvider = $result['source_provider'] ?? 'Unknown';
        $targetProvider = $result['target_provider'] ?? 'Unknown';
        $migrationBatchId = $result['migration_batch_id'] ?? 'Unknown';

        $message = "🔄 Subscription Migration\n".
                   "Source: {$this->getProviderDisplayName($sourceProvider)}\n".
                   "Target: {$this->getProviderDisplayName($targetProvider)}\n".
                   "Batch ID: {$migrationBatchId}\n".
                   'Time: '.now()->toDateTimeString();

        $this->sendTelegramNotification($message);
    }

    /**
     * Record trial completion
     */
    protected function recordTrialCompletion(Subscription $subscription, array $result): void
    {
        $this->orchestrator->recordSubscriptionChange(
            $subscription,
            'trial_completed',
            'Trial period completed',
            ['status' => 'trialing'],
            ['status' => $subscription->status],
            'Trial ended naturally'
        );
    }

    /**
     * Check if event is a coupon usage event
     */
    protected function isCouponUsageEvent(array $result): bool
    {
        $eventType = $result['event_type'] ?? '';

        return in_array($eventType, [
            'coupon.applied',
            'discount.applied',
            'coupon.redeemed',
        ]) || isset($result['coupon_code']);
    }

    /**
     * Check if event is a trial event
     */
    protected function isTrialEvent(array $result): bool
    {
        $eventType = $result['event_type'] ?? '';

        return in_array($eventType, [
            'trial.started',
            'trial.will_end',
            'trial.ending',
            'trial.ended',
            'trial.extended',
        ]) || isset($result['trial_ends_at']);
    }

    /**
     * Check if event is a subscription change event
     */
    protected function isSubscriptionChangeEvent(array $result): bool
    {
        $eventType = $result['event_type'] ?? '';

        return in_array($eventType, [
            'plan.changed',
            'subscription.updated',
            'subscription.paused',
            'subscription.resumed',
            'subscription.cancelled',
        ]) || isset($result['new_plan_id']);
    }

    /**
     * Check if event is a migration event
     */
    protected function isMigrationEvent(array $result): bool
    {
        $eventType = $result['event_type'] ?? '';

        return in_array($eventType, [
            'subscription.migrated',
            'provider.migrated',
        ]) || isset($result['migration_batch_id']);
    }

    /**
     * Determine plan change type
     */
    protected function determinePlanChangeType(?int $oldPlanId, ?int $newPlanId): string
    {
        if (! $oldPlanId || ! $newPlanId) {
            return 'plan_change';
        }

        // This is a simplified determination - in practice you'd compare plan prices/features
        return $newPlanId > $oldPlanId ? 'plan_upgrade' : 'plan_downgrade';
    }

    /**
     * Get display name for provider
     */
    protected function getProviderDisplayName(string $provider): string
    {
        $displayNames = [
            'stripe' => 'Stripe',
            'lemon_squeezy' => 'Lemon Squeezy',
            'polar' => 'Polar.sh',
            'oxapay' => 'OxaPay',
            'crypto' => 'Crypto',
            'activation_key' => 'Activation Key',
        ];

        return $displayNames[$provider] ?? ucfirst($provider);
    }
}
