<?php

namespace App\Repositories\Client;

use App\Models\Client;
use App\Models\OneSignalToken;
use App\Models\Subscription;
use App\Models\SubscriptionTransactionLog;
use App\Repositories\EmailTemplateRepository;
use App\Repositories\PlanRepository;
use App\Traits\SendMailTrait;
use App\Traits\SendNotification;
use Carbon\Carbon;
use Illuminate\Support\Facades\Auth;

class SubscriptionRepository
{
    use SendMailTrait;
    use SendNotification;

    protected $emailTemplate;

    protected $planRepository;

    public function __construct(PlanRepository $planRepository, EmailTemplateRepository $emailTemplate)
    {
        $this->planRepository = $planRepository;
        $this->emailTemplate  = $emailTemplate;
    }

    //client
    public function create($plan, $trx_id, $payment_details, $billingInfo, $offline = false, $payment_method = 'stripe')
    {
        $status       = 1;
        if ($offline) {
            $payment_method  = 'offline';
            $payment_details = json_encode(['payment_type' => 'offline']);
            if (isDemoMode()) {
                $status = 1;
            } else {
                $status = 0;
            }
        }
        $client       = Auth::user()->client;
        $is_recurring = 0;
        $expire_date  = now();

        if ($plan->billing_period == 'daily') {
            $expire_date  = now()->addDay(7);
            $is_recurring = 1;
        }
        if ($plan->billing_period == 'weekly') {
            $expire_date  = now()->addDay(7);
            $is_recurring = 1;
        } elseif ($plan->billing_period == 'monthly') {
            $expire_date  = now()->addMonths();
            $is_recurring = 1;
        } elseif ($plan->billing_period == 'quarterly') {
            $expire_date  = now()->addMonths(3);
            $is_recurring = 1;
        } elseif ($plan->billing_period == 'half_yearly') {
            $expire_date  = now()->addMonths(6);
            $is_recurring = 1;
        } elseif ($plan->billing_period == 'yearly') {
            $expire_date  = now()->addYears();
            $is_recurring = 1;
        }

        $subscription = Subscription::where('client_id', $client->id)->where('status', 1)->first();

        if ($subscription) {
            $subscription->status = 3;
            $subscription->save();
        }

        $this->sendAdminNotifications([
            'message' => __('company_subscribed_to_plan', ['company' => $client->company_name, 'plan' => $plan->name]),
            'heading' => $client->name,
            'url'     => route('packages.subscribe-list'),
        ]);

        if ($offline) {
            $this->sendAdminNotifications([
                'message' => __('offline_payment_waiting_for_approval'),
                'heading' => $client->name,
                'url'     => route('packages.subscribe-list'),
            ]);
        }

        $data         = [
            'client_id'              => $client->id,
            'plan_id'                => $plan->id,
            'is_recurring'           => $is_recurring,
            'status'                 => $status,
            'purchase_date'          => now(),
            'expire_date'            => $expire_date,
            'price'                  => $plan->price,
            'package_type'           => $plan->billing_period,
            'contact_limit'          => $plan->contact_limit,
            'campaign_limit'         => $plan->campaigns_limit,
            'campaign_remaining'     => $plan->campaigns_limit,
            'conversation_limit'     => $plan->conversation_limit,
            'conversation_remaining' => $plan->conversation_limit,
            'team_limit'             => $plan->team_limit,
            'max_chatwidget'         => $plan->max_chatwidget,
            'max_flow_builder'       => $plan->max_flow_builder ?? 0,
            'max_bot_reply'          => $plan->max_bot_reply ?? 0,
            'telegram_access'        => (bool) $plan->telegram_access,
            'messenger_access'       => (bool) $plan->messenger_access,
            'instagram_access'       => (bool) $plan->instagram_access,
            'whatsapp_web_access'    => $plan->whatsapp_web_access,
            'device_limit'           => $plan->device_limit,
            'per_device_credit_limit'=> $plan->per_device_credit_limit,
            'trx_id'                 => $trx_id,
            'payment_method'         => $payment_method,
            'payment_details'        => $payment_details,
            'client'                 => Client::find($client->id),
            'billing_name'           => $billingInfo['billing_name'],
            'billing_email'          => $billingInfo['billing_email'],
            'billing_address'        => $billingInfo['billing_address'],
            'billing_city'           => $billingInfo['billing_city'],
            'billing_state'          => $billingInfo['billing_state'],
            'billing_zip_code'       => $billingInfo['billing_zipcode'],
            'billing_country'        => $billingInfo['billing_country'],
            'billing_phone'          => $billingInfo['billing_phone'],
            'subject'                => __('package_subscription_confirmation'),
        ];

        if (isMailSetupValid()) {
            $this->sendmail($client->user->email, 'emails.purchase_mail', $data);
        }

        session()->forget('billing_info');

        $log          = SubscriptionTransactionLog::create([
            'description' => __('you purchased ') . $plan->name . __('package_successfully'),
            'client_id'                                                   => $client->id
        ]);

        return Subscription::create($data);
    }

    //admin
    public function store($request, $plan, $trx_id, $payment_details, $offline = false, $payment_method = 'stripe')
    {
        $status       = 1;
        if ($offline) {
            $payment_method  = 'offline';
            $payment_details = json_encode(['payment_type' => 'offline']);
            $status          = 1;
        }
        $client       = Client::where('id', $request->client_id)->first();
        $is_recurring = 0;
        $expire_date  = now();

        if ($plan->billing_period == 'daily') {
            $expire_date  = now()->addDay(1);
            $is_recurring = 0;
        }
        if ($plan->billing_period == 'weekly') {
            $expire_date  = now()->addDay(7);
            $is_recurring = 0;
        } elseif ($plan->billing_period == 'monthly') {
            $expire_date  = now()->addMonths();
            $is_recurring = 0;
        } elseif ($plan->billing_period == 'quarterly') {
            $expire_date  = now()->addMonths(3);
            $is_recurring = 0;
        } elseif ($plan->billing_period == 'half_yearly') {
            $expire_date  = now()->addMonths(6);
            $is_recurring = 0;
        } elseif ($plan->billing_period == 'yearly') {
            $expire_date  = now()->addYears();
            $is_recurring = 0;
        }
        $subscription = Subscription::where('client_id', $client->id)->where('status', 1)->first();
        if ($subscription) {
            $subscription->status = 2;
            $subscription->save();
        }

        $data         = [
            'client_id'              => $client->id,
            'plan_id'                => $plan->id,
            'is_recurring'           => $is_recurring,
            'status'                 => $status,
            'purchase_date'          => now(),
            'expire_date'            => $expire_date,
            'price'                  => $request->amount,
            'package_type'           => $plan->billing_period,
            'contact_limit'          => $plan->contact_limit,
            'campaign_limit'         => $plan->campaigns_limit,
            'campaign_remaining'     => $plan->campaigns_limit,
            'conversation_limit'     => $plan->conversation_limit,
            'conversation_remaining' => $plan->conversation_limit,
            'team_limit'             => $plan->team_limit,
            'max_chatwidget'         => $plan->max_chatwidget,
            'max_flow_builder'       => $plan->max_flow_builder ?? 0,
            'max_bot_reply'          => $plan->max_bot_reply ?? 0,
            'telegram_access'        => (bool) $plan->telegram_access,
            'messenger_access'       => (bool) $plan->messenger_access,
            'instagram_access'       => (bool) $plan->instagram_access,
            'whatsapp_web_access'    => $plan->whatsapp_web_access,
            'device_limit'           => $plan->device_limit,
            'per_device_credit_limit'=> $plan->per_device_credit_limit,
            'trx_id'                 => $trx_id,
            'payment_method'         => $payment_method,
            'payment_details'        => $payment_details,
            'client'                 => Client::find($client->id),
        ];
        $log          = SubscriptionTransactionLog::create([
            'description' => 'Admin has purchased ' . $plan->name . ' package for you',
            'client_id'                                                   => $client->id
        ]);

        return Subscription::create($data);
    }

    // public function subscribeListStatus($request, $id)
    // {
    //     $subscribe         = Subscription::findOrfail($id);
    //     $subscribe->status = $request['status'];
    //     if ($request['status'] == 2) {
    //         $payment_method         = $subscribe->payment_method;
    //         if ($payment_method == 'stripe') {
    //             $this->cancelStripe($subscribe);
    //         } elseif ($payment_method == 'paddle') {
    //             $this->cancelPaddle($subscribe);
    //         } elseif ($payment_method == 'paypal') {
    //             $this->cancelPaypal($subscribe);
    //         }
    //         $subscribe->canceled_at = now();
    //     }
    //     $status            = __('pending');
    //     if ($request['status'] == 1) {
    //         $status = __('active');
    //     } elseif ($request['status'] == 2) {
    //         $status = __('cancelled');
    //     } elseif ($request['status'] == 3) {
    //         $status = __('rejected');
    //     }
    //     $msg               = __('subscription_status_updated', ['status' => $status]);
    //     $this->pushNotification([
    //         'ids'     => OneSignalToken::where('client_id', $subscribe->client_id)->pluck('subscription_id')->toArray(),
    //         'message' => $msg,
    //         'heading' => __('status_has_been_updated'),
    //         'url'     => route('client.dashboard'),
    //     ]);
    //     $this->sendNotification([$subscribe->client->user->id], $msg, 'success', route('client.dashboard'));

    //     $log               = SubscriptionTransactionLog::create([
    //         'description' => 'Admin ' . $status . ' your plan',
    //         'client_id'                                                        => $subscribe->client_id
    //     ]);

    //     return $subscribe->save();
    // }

    public function subscribeListStatus($request, $id)
    {
        // Find subscription
        $subscribe = Subscription::findOrFail($id);
        $status = (int) $request['status'];

        // Update subscription status
        $subscribe->status = $status;

        // If the new status is "cancelled"
        if ($status === 2) {
            $paymentMethod = $subscribe->payment_method;

            // Cancel subscription based on payment method
            switch ($paymentMethod) {
                case 'stripe':
                    $this->cancelStripe($subscribe);
                    break;
                case 'paddle':
                    $this->cancelPaddle($subscribe);
                    break;
                case 'paypal':
                    $this->cancelPaypal($subscribe);
                    break;
            }

            // Set cancellation date
            $subscribe->canceled_at = now();
        }

        // Save changes to the subscription
        $subscribe->save();

        // Determine readable status name
        $statusText = match ($status) {
            1 => __('active'),
            2 => __('cancelled'),
            3 => __('rejected'),
            default => __('pending'),
        };

        // Message to send
        $msg = __('subscription_status_updated', ['status' => $statusText]);

        // Push notification to OneSignal users
        $subscriptionIds = OneSignalToken::where('client_id', $subscribe->client_id)
            ->pluck('subscription_id')
            ->toArray();

        $this->pushNotification([
            'ids'     => $subscriptionIds,
            'message' => $msg,
            'heading' => __('status_has_been_updated'),
            'url'     => route('client.dashboard'),
        ]);

        // In-app notification to client user (optional() handles nulls)
        if ($subscribe->client && $subscribe->client->user) {
            $this->sendNotification(
                [$subscribe->client->user->id],
                $msg,
                'success',
                route('client.dashboard')
            );
        }

        // Log the subscription status update
        SubscriptionTransactionLog::create([
            'description' => 'Admin ' . $statusText . ' your plan',
            'client_id'   => $subscribe->client_id,
        ]);
        // Return updated subscription
        return $subscribe;
    }



    public function updateSubscriptionLimits($subscriptionId, $newLimits)
    {
        $subscription = Subscription::findOrFail($subscriptionId);
        $subscription->contact_limit          += intval($newLimits['new_contacts_limit']);
        $subscription->campaign_remaining     += intval($newLimits['new_campaigns_limit']);
        $subscription->campaign_limit         += intval($newLimits['new_campaigns_limit']);
        $subscription->conversation_remaining += intval($newLimits['new_conversation_limit']);
        $subscription->conversation_limit     += intval($newLimits['new_conversation_limit']);
        $subscription->team_limit             += intval($newLimits['new_team_limit']);
        $subscription->max_chatwidget         += intval($newLimits['new_max_chatwidget']);
        $subscription->max_flow_builder      += intval($newLimits['new_max_flow_builder']);
        $subscription->max_bot_reply         += intval($newLimits['new_max_bot_reply']);

        $log          = SubscriptionTransactionLog::create([
            'description' => 'Admin update some credit in your Subscription',
            'client_id'                                                   => $subscription->client_id
        ]);
        $subscription->save();

        return $subscription;
    }

    public function cancelSubscription($id)
    {
        $subscription              = Subscription::find($id);

        $payment_method            = $subscription->payment_method;

        // Cancel recurring subscription at payment gateway level
        // This ensures automatic recurring billing is stopped
        try {
            if ($payment_method == 'stripe') {
                $this->cancelStripe($subscription);
            } elseif ($payment_method == 'paddle') {
                $this->cancelPaddle($subscription);
            } elseif ($payment_method == 'paypal') {
                $this->cancelPaypal($subscription);
            }
        } catch (\Exception $e) {
            // Log error but continue with cancellation process
            // Even if gateway cancellation fails, we still disable recurring in database
            logError('Payment gateway cancellation error: ', $e);
        }

        // Disable recurring in database - this is critical to prevent any future recurring charges
        // This ensures recurring is disabled even if payment gateway call fails
        $subscription->is_recurring = 0;
        $subscription->canceled_at = now();
        
        // Keep status as 1 (active) so client can access until expire_date
        // Status will be automatically invalidated when expire_date passes
        $subscription->status      = 1;
        
        $log                       = SubscriptionTransactionLog::create([
            'description' => 'You cancel Your Subscription. Recurring billing has been disabled. Access will continue until ' . Carbon::parse($subscription->expire_date)->format('Y-m-d'),
            'client_id'   => auth()->user()->client_id
        ]);
        $subscription->save();

        // Also ensure any other active subscriptions for this client have recurring disabled
        // This is a safety measure in case there are multiple subscriptions
        Subscription::where('client_id', $subscription->client_id)
            ->where('id', '!=', $subscription->id)
            ->where('is_recurring', 1)
            ->where('status', 1)
            ->update(['is_recurring' => 0]);

        return $subscription;
    }

    public function stopRecurring($id)
    {
        $subscription               = Subscription::find($id);

        $payment_method             = $subscription->payment_method;

        if ($payment_method == 'stripe') {
            $this->cancelStripe($subscription);
        } elseif ($payment_method == 'paddle') {
            $this->cancelPaddle($subscription);
        } elseif ($payment_method == 'paypal') {
            $this->cancelPaypal($subscription);
        }
        $cancel_date                = Carbon::parse($subscription->purchase_date);
        if ($subscription->package_type == 'daily') {
            $cancel_date = $cancel_date->addDay();
        } elseif ($subscription->package_type == 'weekly') {
            $cancel_date = $cancel_date->addWeek();
        } elseif ($subscription->package_type == 'monthly') {
            $cancel_date = $cancel_date->addMonth();
        } elseif ($subscription->package_type == 'quarterly') {
            $cancel_date = $cancel_date->addMonths(3);
        } elseif ($subscription->package_type == 'half_yearly') {
            $cancel_date = $cancel_date->addMonths(6);
        } elseif ($subscription->package_type == 'yearly') {
            $cancel_date = $cancel_date->addYear();
        }
        $subscription->canceled_at  = $cancel_date;
        $subscription->is_recurring = 0;

        if (auth()->user()->user_type == 'admin') {
            $log = SubscriptionTransactionLog::create([
                'description' => 'admin stop your recurring',
                'client_id'                                          => $subscription->client_id
            ]);
        } else {
            $log = SubscriptionTransactionLog::create([
                'description' => 'you stop your recurring',
                'client_id'                                          => $subscription->client_id
            ]);
        }

        $subscription->save();

        return $subscription;
    }

    public function enableRecurring($id)
    {
        $subscription               = Subscription::find($id);

        $payment_method             = $subscription->payment_method;

        if ($payment_method == 'stripe') {
            $this->cancelStripe($subscription);
        } elseif ($payment_method == 'paddle') {
            $this->cancelPaddle($subscription);
        } elseif ($payment_method == 'paypal') {
            $this->cancelPaypal($subscription);
        }
        $cancel_date                = Carbon::parse($subscription->purchase_date);
        if ($subscription->package_type == 'daily') {
            $cancel_date = $cancel_date->addDay();
        } elseif ($subscription->package_type == 'weekly') {
            $cancel_date = $cancel_date->addWeek();
        } elseif ($subscription->package_type == 'monthly') {
            $cancel_date = $cancel_date->addMonth();
        } elseif ($subscription->package_type == 'quarterly') {
            $cancel_date = $cancel_date->addMonths(3);
        } elseif ($subscription->package_type == 'half_yearly') {
            $cancel_date = $cancel_date->addMonths(6);
        } elseif ($subscription->package_type == 'yearly') {
            $cancel_date = $cancel_date->addYear();
        }
        $subscription->canceled_at  = $cancel_date;
        $subscription->is_recurring = 1;
        $log                        = SubscriptionTransactionLog::create([
            'description' => 'You enable subscription recurring',
            'client_id'                                                                 => $subscription->client_id
        ]);
        $subscription->save();

        return $subscription;
    }

    public function cancelStripe($subscription)
    {
        // Try to get Stripe subscription ID from payment_details
        // It can be stored as 'subscription_id' or 'subscription' depending on when it was created
        $stripe_subscript_id = getArrayValue('subscription_id', $subscription->payment_details) 
                            ?? getArrayValue('subscription', $subscription->payment_details);
        
        $response = [];
        
        if ($stripe_subscript_id) {
            try {
                $headers  = [
                    'Authorization' => 'Basic ' . base64_encode(setting('stripe_secret') . ':'),
                    'Content-Type'  => 'application/x-www-form-urlencoded',
                ];

                $data     = [
                    'invoice_now' => 'false',
                ];
                
                // DELETE request to Stripe API to cancel the subscription
                // This will immediately stop all future recurring charges
                $response = httpRequest('https://api.stripe.com/v1/subscriptions/' . $stripe_subscript_id, $data, $headers, true, 'DELETE');
                
                // Log successful cancellation
                if (isset($response['id'])) {
                    \Log::info("Stripe subscription cancelled successfully", [
                        'subscription_id' => $stripe_subscript_id,
                        'client_id' => $subscription->client_id
                    ]);
                }
            } catch (\Exception $e) {
                // Log error but don't throw - we'll still disable recurring in database
                logError('Stripe subscription cancellation error: ', $e);
            }
        } else {
            // Log warning if subscription ID not found
            \Log::warning("Stripe subscription ID not found in payment_details", [
                'subscription_id' => $subscription->id,
                'client_id' => $subscription->client_id,
                'payment_method' => $subscription->payment_method
            ]);
        }

        return $response;
    }

    public function cancelPaddle($subscription)
    {
        $transaction_id  = $subscription->payment_details['transaction_id'];

        $headers         = [
            'Authorization' => 'Bearer ' . setting('paddle_api_key'),
        ];
        if (setting('is_paddle_sandbox_mode_activated')) {
            $base_url = 'https://sandbox-api.paddle.com/';
        } else {
            $base_url = 'https://api.paddle.com/';
        }
        $data            = [
            'effective_from' => 'next_billing_period',
        ];
        $response        = httpRequest($base_url . "transactions/$transaction_id", $data, $headers, false, 'GET');
        $subscription_id = $response['data']['subscription_id'];

        return httpRequest($base_url . "subscriptions/$subscription_id/cancel", $data, $headers);
    }

    public function paypalTokenGenerator($base_url): string
    {
        //generate access token
        $headers  = [
            'Content-Type'  => 'application/x-www-form-urlencoded',
            'Authorization' => 'Basic ' . base64_encode(setting('paypal_client_id') . ':' . setting('paypal_client_secret')),
        ];
        $data     = [
            'grant_type' => 'client_credentials',
        ];
        $response = httpRequest($base_url . '/v1/oauth2/token', $data, $headers, true);

        return $response['token_type'] . ' ' . $response['access_token'];
    }

    public function cancelPaypal($subscription)
    {
        if (setting('is_paypal_sandbox_mode_activated')) {
            $base_url = 'https://api-m.sandbox.paypal.com';
        } else {
            $base_url = 'https://api-m.paypal.com';
        }
        $paypal_subscription_id = $subscription->payment_details['id'];
        $headers                = [
            'Content-Type'  => 'application/json',
            'Authorization' => $this->paypalTokenGenerator($base_url),
        ];

        $data                   = [
            'reason' => 'stopped by admin',
        ];

        return httpRequest($base_url . '/v1/billing/subscriptions/' . $paypal_subscription_id . '/cancel', $data, $headers);
    }

    public function updateValidity($data, $id)
    {
        $subscription                  = Subscription::find($id);

        $date                          = '';
        if ($data['interval'] == 'day') {
            $date = Carbon::parse($subscription->expire_date)->addDays($data['time']);
        } elseif ($data['interval'] == 'week') {
            $date = Carbon::parse($subscription->expire_date)->addWeeks($data['time']);
        } elseif ($data['interval'] == 'month') {
            $date = Carbon::parse($subscription->expire_date)->addMonths($data['time']);
        } elseif ($data['interval'] == 'year') {
            $date = Carbon::parse($subscription->expire_date)->addYears($data['time']);
        }

        $payment_details               = $subscription->payment_details;
        $payment_method                = $subscription->payment_method;
        if ($payment_method == 'stripe') {
            $payment_details = $this->updateStripe($subscription, $date->timestamp);
        } elseif ($payment_method == 'paddle') {
            $payment_details = $this->updatePaddle($subscription);
        } elseif ($payment_method == 'paypal') {
            $payment_details = $this->updatePaypal($subscription);
        }
        $subscription->payment_details = $payment_details;
        $subscription->expire_date     = $date;
        $subscription->save();

        return $subscription;
    }

    public function updateStripe($subscription, $date)
    {
        $this->cancelStripe($subscription);

        $headers = [
            'Authorization' => 'Basic ' . base64_encode(setting('stripe_secret') . ':'),
            'Content-Type'  => 'application/x-www-form-urlencoded',
        ];
        $url     = 'https://api.stripe.com/v1/subscriptions';

        $fields  = [
            'customer'             => $subscription->payment_details['customer'],
            'currency'             => 'USD',
            'items'                => [
                [
                    'price'    => $this->planRepository->getPGCredential($subscription->plan_id, 'stripe'),
                    'quantity' => 1,
                ],
            ],
            'billing_cycle_anchor' => $date,
        ];

        return httpRequest($url, $fields, $headers, true);
    }
}
