<?php

declare(strict_types=1);

namespace App\Listeners;

use App\Events\SubscriptionCancelled;
use App\Models\WinbackCampaign;
use App\Models\WinbackRecipient;
use App\Notifications\SubscriptionCancelledNotification;
use App\Services\Provisioning\ProvisioningFactory;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Log;

class HandleSubscriptionCancelled implements ShouldQueue
{
    public $tries = 3;

    public $backoff = [60, 120, 300];

    public function __construct(
        private ProvisioningFactory $provisioningFactory,
    ) {}

    public function handle(SubscriptionCancelled $event): void
    {
        Log::info("Subscription cancelled for user #{$event->user->id}", [
            'subscription_id' => $event->subscription->id,
            'type' => $event->subscription->type,
        ]);

        // Terminate associated services (VirtFusion handles delay)
        $services = $event->user->services()
            ->where('subscription_id', $event->subscription->id)
            ->whereIn('status', ['active', 'suspended', 'failed', 'pending'])
            ->where(function ($query): void {
                // Exclude pending services without a platform ID — they may be mid-provisioning
                // and will be cleaned up by RetryProvisioningCommand if they fail
                $query->where('status', '!=', 'pending')
                    ->orWhereNotNull('platform_service_id');
            })
            ->get();

        foreach ($services as $service) {
            try {
                // If service was never provisioned (no platform ID), just mark it terminated
                if (! $service->platform_service_id) {
                    $service->update([
                        'status' => 'terminated',
                        'terminated_at' => now(),
                    ]);

                    Log::info('Service marked terminated (no platform service)', [
                        'service_id' => $service->id,
                        'subscription_id' => $event->subscription->id,
                    ]);
                } elseif ($service->service_type) {
                    // Use service_type directly from the Service record — avoids dependency on plan_id
                    $provisioner = $this->provisioningFactory->make($service->service_type);
                    $provisioner->terminate($service);

                    Log::info('Service terminated successfully', [
                        'service_id' => $service->id,
                        'subscription_id' => $event->subscription->id,
                        'service_type' => $service->service_type,
                    ]);
                } else {
                    Log::warning('Subscription cancelled but could not determine service type for termination', [
                        'subscription_id' => $event->subscription->id,
                        'service_id' => $service->id,
                        'platform_service_id' => $service->platform_service_id,
                    ]);
                }
            } catch (\Exception $e) {
                Log::error('Service termination exception', [
                    'service_id' => $service->id,
                    'subscription_id' => $event->subscription->id,
                    'error' => $e->getMessage(),
                ]);
            }
        }

        $event->user->notify(new SubscriptionCancelledNotification($event->subscription));

        // Enroll in matching win-back campaign
        $this->enrollInWinbackCampaign($event);
    }

    private function enrollInWinbackCampaign(SubscriptionCancelled $event): void
    {
        try {
            if ($event->cancellationReason) {
                $campaign = WinbackCampaign::active()->forReason($event->cancellationReason)->first();
            } else {
                $campaign = WinbackCampaign::active()->whereNull('cancellation_reason')->first();
            }

            if ($campaign) {
                WinbackRecipient::firstOrCreate([
                    'campaign_id' => $campaign->id,
                    'user_id' => $event->user->id,
                    'subscription_id' => $event->subscription->id,
                ]);

                Log::info('User enrolled in win-back campaign', [
                    'user_id' => $event->user->id,
                    'campaign_id' => $campaign->id,
                    'reason' => $event->cancellationReason,
                ]);
            }
        } catch (\Exception $e) {
            Log::error('Failed to enroll user in win-back campaign', [
                'user_id' => $event->user->id,
                'error' => $e->getMessage(),
            ]);
        }
    }
}
