<?php

namespace App\Console\Commands;

use App\Models\Setting;
use App\Models\Subscription;
use App\Models\User;
use App\Notifications\SubscriptionExpired;
use App\Notifications\SubscriptionExpiringSoon;
use Carbon\Carbon;
use Illuminate\Console\Command;

class CheckExpiringSubscriptions extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'subscriptions:check-expiring
                            {--days=7 : Days before expiration to check}
                            {--grace=3 : Grace period days after expiration}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Check for subscriptions expiring soon and expired, notify users and process expirations';

    /**
     * Execute the console command.
     */
    public function handle()
    {
        $days = (int) $this->option('days');
        $gracePeriod = (int) Setting::get('subscription_grace_period_days', $this->option('grace'));

        $this->info("Checking subscriptions expiring in {$days} days or less...");
        $this->info("Grace period: {$gracePeriod} days");

        // 1. Notify subscriptions expiring soon (still active)
        $this->checkExpiringSoon($days);

        // 2. Process expired subscriptions (with grace period)
        $this->processExpired($gracePeriod);

        // 3. Process subscriptions past grace period (fully deactivate)
        $this->processExpiredPastGrace($gracePeriod);

        return Command::SUCCESS;
    }

    /**
     * Notify users about subscriptions expiring soon.
     */
    protected function checkExpiringSoon(int $days): void
    {
        $expiringSubscriptions = Subscription::where('status', 'active')
            ->where('end_date', '<=', Carbon::now()->addDays($days))
            ->where('end_date', '>', Carbon::now())
            ->whereNull('expiring_notified_at') // Only notify once
            ->with(['user', 'plan'])
            ->get();

        $count = 0;
        foreach ($expiringSubscriptions as $subscription) {
            if ($subscription->user) {
                $daysRemaining = Carbon::now()->diffInDays($subscription->end_date, false);

                $subscription->user->notify(new SubscriptionExpiringSoon($subscription, max(1, $daysRemaining)));
                $subscription->update(['expiring_notified_at' => now()]);

                $this->info("Notified {$subscription->user->name} - expires in {$daysRemaining} days");
                $count++;
            }
        }

        $this->info("Total: {$count} expiring subscription notifications sent.");
    }

    /**
     * Process newly expired subscriptions (within grace period).
     */
    protected function processExpired(int $gracePeriod): void
    {
        $expiredSubscriptions = Subscription::where('status', 'active')
            ->where('end_date', '<', Carbon::now())
            ->where('end_date', '>=', Carbon::now()->subDays($gracePeriod))
            ->whereNull('expired_notified_at') // Only notify once
            ->with(['user', 'plan'])
            ->get();

        foreach ($expiredSubscriptions as $subscription) {
            // Mark as expired but in grace period
            $subscription->update([
                'status' => 'expired',
                'expired_notified_at' => now(),
            ]);

            if ($subscription->user) {
                $subscription->user->notify(new SubscriptionExpired($subscription, $gracePeriod));
                $this->warn("Marked subscription #{$subscription->id} as expired (grace period: {$gracePeriod} days)");
            }
        }

        $this->info("Total: {$expiredSubscriptions->count()} subscriptions marked as expired (in grace period).");
    }

    /**
     * Process subscriptions past grace period - fully deactivate.
     */
    protected function processExpiredPastGrace(int $gracePeriod): void
    {
        $pastGraceSubscriptions = Subscription::where('status', 'expired')
            ->where('end_date', '<', Carbon::now()->subDays($gracePeriod))
            ->whereNull('fully_deactivated_at')
            ->with(['user', 'plan'])
            ->get();

        foreach ($pastGraceSubscriptions as $subscription) {
            $subscription->update([
                'fully_deactivated_at' => now(),
                'auto_renew' => false,
            ]);

            if ($subscription->user) {
                // Send final notification
                $subscription->user->notify(new SubscriptionExpired($subscription, 0));
                $this->error("Subscription #{$subscription->id} fully deactivated (past grace period)");
            }
        }

        $this->info("Total: {$pastGraceSubscriptions->count()} subscriptions fully deactivated.");
    }
}
