<?php

namespace MtcPharmacy\Subscriptions;

use Mtc\Shop\Order;
use Mtc\Shop\Basket;
use Mtc\Core\Admin\Menu;
use Mtc\Shop\Events\OrderPaidEvent;
use App\Events\AssessmentInitEvent;
use App\Events\AssessmentCreatedEvent;
use Mtc\Shop\Assessment\Assessment;
use Mtc\Modules\Members\Classes\Auth;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
use Mtc\Shop\Events\AddToBasketEvent;
use Illuminate\Support\ServiceProvider;
use Mtc\Shop\Basket\Item as BasketItem;
use MtcPharmacy\Subscriptions\Classes\Subscription;
use MtcPharmacy\Subscriptions\Classes\SubscriptionLog;
use MtcPharmacy\Subscriptions\Classes\SubscriptionPreference;

class SubscriptionsServiceProvider extends ServiceProvider
{
    const MENU_SUBSCRIPTIONS = 'Subscriptions';
    const MENU_SUBSCRIPTION_LOGS = 'Subscription Logs';

    public function boot(): void
    {
        $this->loadRoutesFrom(__DIR__ . '/routes/web.php');
        $this->loadMigrationsFrom(__DIR__ . '/database/migrations');

        // Pharmacy platform uses custom twig template loaders.
        $view_paths = config('view.paths');
        $view_paths[] = __DIR__ . '/templates';
        config(['view.paths' => $view_paths]);

        // Only inject admin menu items when we’re not in CLI
        if (!app()->runningInConsole()) {
            $this->injectAdminMenuItems();
        }

        $this->configureListeners();
    }

    private function configureListeners()
    {
        if (config('subscription.enabled')) {
            Event::listen(
                'Mtc\Shop\Events\AddToBasketEvent',
                function (AddToBasketEvent $event) {

					$event_params = $event->getParams();

					if(!empty($event_params['basket_item_id'])) {


						$basket_item_id = $event_params['basket_item_id'];
						$basket_item = BasketItem::find($basket_item_id);

						if ($basket_item) {
							$purchase_type = $event->getRequest()['purchase_type'] ?? null;
							if ($purchase_type == 'subscription') {

								$basket_item->has_requested_subscription = true;

								$query = SubscriptionPreference::query()->where('item_id', $basket_item->item_id);

								if ($basket_item->sizeid != 0) {
									$query->where('item_size_id', $basket_item->sizeid);
								}

								$sub_config = $query->first();

								if ($sub_config) {
									$period = ((int)$sub_config->interval_multiplier > 0 && !empty($sub_config->interval))
										? $sub_config->interval_multiplier . ' ' . $sub_config->interval
										: '1 months';
									$basket_item->has_requested_subscription_period = $period;
									$basket_item->save();
								} else {
									$basket_item->has_requested_subscription_period = '1 months';
									$basket_item->save();
								}
							}
						}

					}


                }
            );
        }

        // Subscription re-assessment: detect when assessment is loaded from a subscription email link
        if (config('subscription.enabled')) {
            Event::listen(AssessmentInitEvent::class, function (AssessmentInitEvent $event) {
                $request = $event->getRequest();

                if ($request->input('redirect-type') !== 'subscription' || !$request->input('subscription_id')) {
                    return;
                }

                $subscriptionId = (int) $request->input('subscription_id');
                $member = Auth::getLoggedInMember();

                if (empty($member->id)) {
                    return;
                }

                $subscription = Subscription::where('id', $subscriptionId)
                    ->where('member_id', $member->id)
                    ->where('status', Subscription::STATUS_ACTIVE)
                    ->first();

                if ($subscription) {
                    session(['subscription_reassessment_id' => $subscription->id]);
                }
            });

            Event::listen(AssessmentCreatedEvent::class, function (AssessmentCreatedEvent $event) {
                $subscriptionId = session('subscription_reassessment_id');

                if (!$subscriptionId) {
                    return;
                }

                $assessment = $event->getAssessment();

                if (!$assessment->is_completed) {
                    return;
                }

                $subscription = Subscription::find($subscriptionId);

                if (!$subscription) {
                    session()->forget('subscription_reassessment_id');
                    return;
                }

                // Reload answers relationship — it may be stale since answers were added after the model was created
                $assessment->load('answers.question');

                // Extend expiry date based on new assessment answers
                $subscription->expiry_date = $assessment->getExpiryDate(365);
                $subscription->is_assessment_updated = 1;
                $subscription->save();

                // Update subscription item's assessment_id
                foreach ($subscription->items as $item) {
                    $item->assessment_id = $assessment->id;
                    $item->save();
                }

                SubscriptionLog::logAction(
                    $subscription->id,
                    SubscriptionLog::ACTION_UPDATED,
                    "Assessment renewed - expiry date updated to {$subscription->expiry_date}",
                    null,
                    null,
                    ['assessment_id' => $assessment->id],
                    SubscriptionLog::SOURCE_CUSTOMER
                );

                // Set redirect so the Vue form sends the user back to subscriptions page
                session()->now(Assessment::ASSESSMENT_COMPLETE_REDIRECT, '/member/orders/subscriptions?assessment_renewed=1');
                session()->forget('subscription_reassessment_id');
            });
        }

        if (config('subscription.enabled')) {
            Event::listen('subscriptions.paymentFailed', function ($subscription) {
                try {
                    $template = 'emails/shop/payment_failed.twig';

                    $subscription->previous_payment_id = null;
                    $subscription->status = Subscription::STATUS_PAYMENT_FAILED;
                    $subscription->save();

                    // Update basket for the failed payment so that subscription is included in the basket
                    $failedOrder = $subscription->getLatestFailedPayment();

                    if (!$failedOrder) {
                        Log::error("No failed order found for subscription {$subscription->id}");
                        return;
                    }

                    SubscriptionLog::logPaymentFailed(
                        $subscription,
                        $failedOrder->total ?? 0,
                        'Payment failed',
                        SubscriptionLog::SOURCE_SYSTEM,
                        ['command' => 'payment_failed', 'order_id' => $failedOrder->id]
                    );

                    $basket = Basket::query()->find($failedOrder->basket_id);
                    if ($basket) {
                        foreach ($basket->items as $item) {
                            $item->has_requested_subscription = 1;
                            $item->save();
                        }
                    }

                    $body = app('twig')->render($template, [
                        'order' => $failedOrder,
                        'payment_url' => SITE_URL . '/shop/checkout/basket_overview.php?order_id=' . $failedOrder->id
                    ]);

                    $customer_email_address = $subscription->member->email;
                    $subject = 'Payment failed';

                    email($customer_email_address, $subject, $body, [
                        'queue' => true,
                        'bcc' => config('site.shop_email'),
                    ]);

                    SubscriptionLog::logEmailSent(
                        $subscription,
                        $subject,
                        'payment_failed',
                        SubscriptionLog::SOURCE_SYSTEM,
                        ['command' => 'payment_failed', 'order_id' => $failedOrder->id]
                    );
                } catch (\Exception $e) {
                    Log::error("Error sending payment failed email for subscription {$subscription->id}: " . $e->getMessage());
                    Log::error($e->getTraceAsString());
                }
            });
        }
    }

    public function register()
    {
        $this->mergeConfigFrom(__DIR__ . '/config/subscription.php', 'subscription');

        // Register commands
        if ($this->app->runningInConsole()) {
            $this->commands([
                \MtcPharmacy\Subscriptions\Console\Commands\SetupTestSubscriptionCommand::class,
                \MtcPharmacy\Subscriptions\Console\Commands\ShowSubscriptionCommand::class,
            ]);
        }

        Event::listen(OrderPaidEvent::class, function (OrderPaidEvent $event) {
            if (!config('subscription.enabled')) {
                return;
            }

            try {
                $order = Order::query()->find($event->getOrder()->getId());

                if (!$order) {
                    Log::error('OrderPaidEvent: Order not found', [
                        'order_id' => $event->getOrder()->getId(),
                    ]);
                    return;
                }

                // If retrying a specific failed subscription payment, only activate that one
                $retrySubscriptionId = $_SESSION['retry_subscription_id'] ?? null;
                if ($retrySubscriptionId) {
                    unset($_SESSION['retry_subscription_id']);
                    $subscription = $order->subscriptions()
                        ->where('subscriptions.id', $retrySubscriptionId)
                        ->where('status', Subscription::STATUS_PAYMENT_FAILED)
                        ->first();
                } else {
                    // For new orders, activate the first pending subscription
                    $subscription = $order->subscriptions()
                        ->whereIn('status', [
                            Subscription::STATUS_PENDING,
                            Subscription::STATUS_PAYMENT_FAILED,
                        ])
                        ->first();
                }

                if ($subscription) {
                    $subscription->setActive();
                    Log::info('Subscription activated after payment', [
                        'subscription_id' => $subscription->id,
                        'order_id' => $order->id,
                    ]);
                }
            } catch (\Exception $e) {
                Log::error('Failed to activate subscription after payment', [
                    'order_id' => $event->getOrder()->getId(),
                    'error' => $e->getMessage(),
                    'trace' => $e->getTraceAsString(),
                ]);

                // Optionally notify admins of critical payment processing failure
                // You could dispatch a notification event here
            }
        });
    }

    /**
     * Injects menu items in admin menu
     *
     * @return void
     */
    protected function injectAdminMenuItems(): void
    {
        $cacheKey = 'admin_menu:subscriptions_installed';

        // If we already created it, skip entirely (no DB hit)
        if (Cache::get($cacheKey) === true) {
            return;
        }

        // One-time DB check; result cached forever to avoid repeated queries
        $alreadyExists = Cache::rememberForever('admin_menu:subscriptions_exists', function () {
            return Menu::query()->where('title', self::MENU_SUBSCRIPTIONS)->exists();
        });

        if ($alreadyExists) {
            Cache::forever($cacheKey, true);
            return;
        }

        // Create under Clinic (guarded)
        $clinicMenu = Cache::rememberForever('admin_menu:clinic_node', function () {
            return Menu::query()->where('title', 'Clinic')->first()?->id;
        });

        if (!$clinicMenu) {
            // No clinic; to avoid hammering, set a short TTL backoff
            Cache::put('admin_menu:subscriptions_exists', false, now()->addMinutes(10));
            return;
        }

        Menu::query()->updateOrInsert(
            ['sub_id' => $clinicMenu, 'title' => self::MENU_SUBSCRIPTIONS],
            ['icon' => 'fa fa-refresh', 'path' => '/admin/subscriptions', 'activePath' => '/admin/subscriptions', 'order' => '2']
        );

        Menu::query()->updateOrInsert(
            ['sub_id' => $clinicMenu, 'title' => self::MENU_SUBSCRIPTION_LOGS],
            ['icon' => 'fa fa-refresh', 'path' => '/admin/subscription-logs', 'activePath' => '/admin/subscription-logs', 'order' => '2']
        );

        // Mark installed; future requests won’t query
        Cache::forever($cacheKey, true);
    }
}
