<?php

namespace App\Console\Commands;

use App\Models\Order;
use App\Models\Subscription;
use App\Services\SubscriptionService;
use Illuminate\Console\Command;

class SubscriptionRenewal extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'cp:subscription-renewal';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Command description';

    /**
     * Execute the console command.
     */
    public function handle()
    {
        /**
         * if billing date is today, just created the order with pending status and notify the user about payment and keep the subscription active
         * on next day, check if the last order is still pending, move subscription status to SUBSCRIPTION_STATUS_PAST_DUE and notify the user
         * after grace period, if the last order is still pending, move subscription status to SUBSCRIPTION_STATUS_SUSPENDED and notify the user
         * if the last order is still pending after 3 days, move subscription status to SUBSCRIPTION_STATUS_CANCELLED and notify the user
         *
         * if billing_count is reached, move subscription status to SUBSCRIPTION_STATUS_EXPIRED and notify the user
         */
        $subscriptions = Subscription::where(function ($query) {
            $query->whereIn('status', [
                getConstant('SUBSCRIPTION_STATUS_ACTIVE'),
                getConstant('SUBSCRIPTION_STATUS_PAST_DUE'),
                getConstant('SUBSCRIPTION_STATUS_SUSPENDED')
            ])
                ->whereDate('next_billing_date', '<=', now());
        })
            ->orWhere(function ($query) {
                $query->where('trial_active', 1)
                    ->where('status', getConstant('SUBSCRIPTION_STATUS_TRIAL'))
                    ->whereDate('trial_end_date', '<=', now());
            })
            ->orWhere(function ($query) {
                $query->whereNotNull('cancelled_at')
                    ->whereDate('next_billing_date', '<', now());
            })
            ->get();

        $subscriptionService = app()->make(SubscriptionService::class);

        if ($subscriptions->isEmpty()) {
            $this->info('No subscriptions to process.');
            return;
        }

        foreach ($subscriptions as $sub) {
            if ($sub->cancelled_at) {
                $subscriptionService->processCustomerCancelledSubscriptions($sub);
                $this->info('Subscription ID: ' . $sub->id . ' is cancelled on customer request after date.');
                continue;
            }

            // Trial end date ka check add kiya gaya hai
            if ($sub->trial_active && now()->greaterThanOrEqualTo($sub->trial_end_date)) {
                $subscriptionService->moveTrialSubscriptionToExpired($sub);
                $this->info('Trail Subscription ID: ' . $sub->id . ' moved to expired.');
            }

            $overdueDays = now()->diffInDays($sub->next_billing_date, false) * -1;
            /**
             * If overdueDays is 0, it’s due today.
             * If overdueDays is 1, it’s 1 day overdue.
             * If overdueDays is 3, it’s 3 days overdue, etc.
             */

            $allOrders = Order::where('subscription_id', $sub->id)->where('status', getConstant('ORDER_STATUS_COMPLETED'))->get();
            if ($overdueDays >= 1 && $sub->billing_cycle == $allOrders->count() && $sub->status === getConstant('SUBSCRIPTION_STATUS_ACTIVE')) {
                $subscriptionService->moveSubscriptionToExpired($sub);
                $this->info('Subscription ID: ' . $sub->id . ' moved to expired.');
                continue;
            }

            $lastOrder = Order::where('subscription_id', $sub->id)->latest('id')->first();
            $lastOrderTime = now()->diffInDays($lastOrder->created_at, false) * -1;
            $newOrderTime = (int)setting('subscription.renewal_order_creation_delay', '0');
            $subPastDueTime = (int)setting('subscription.overdue_status_change_delay', '1') + $newOrderTime;
            $subSuspendTime = (int)setting('subscription.suspended_status_change_delay', '3') + $subPastDueTime;
            $subCancelTime = (int)setting('subscription.suspended_status_change_delay', '5') + $subSuspendTime;

            // Modification: Use >= for missed days, and add pending order check
            if ($overdueDays >= $newOrderTime && $sub->status === getConstant('SUBSCRIPTION_STATUS_ACTIVE') && $lastOrder->status === getConstant('ORDER_STATUS_COMPLETED')) {
                // Ensure there's no pending order already
                $pendingOrder = Order::where('subscription_id', $sub->id)->where('status', getConstant('ORDER_STATUS_PENDING'))->first();
                if (!$pendingOrder) {
                    $subscriptionService->createOrder($sub);
                    $this->info('Order created for Subscription ID: ' . $sub->id);
                }
            } elseif ($overdueDays >= $subPastDueTime && $sub->status === getConstant('SUBSCRIPTION_STATUS_ACTIVE') && $lastOrder->status === getConstant('ORDER_STATUS_PENDING')) {
                $subscriptionService->moveSubscriptionToPastDue($sub);
                $this->info('Subscription ID: ' . $sub->id . ' moved to past due.');
            } elseif ($overdueDays >= $subSuspendTime && $sub->status === getConstant('SUBSCRIPTION_STATUS_PAST_DUE') && $lastOrder->status === getConstant('ORDER_STATUS_PENDING')) {
                $subscriptionService->moveSubscriptionToSuspended($sub);
                $this->info('Subscription ID: ' . $sub->id . ' moved to suspended.');
            } elseif ($overdueDays >= $subCancelTime && $sub->status === getConstant('SUBSCRIPTION_STATUS_SUSPENDED') && $lastOrder->status === getConstant('ORDER_STATUS_PENDING')) {
                $subscriptionService->moveSubscriptionToCancelled($sub);
                $this->info('Subscription ID: ' . $sub->id . ' moved to cancelled.');
            }
        }
    }
}
