<?php

namespace App\Http\Controllers;

use App\Interfaces\OrganisationRepositoryInterface;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use App\Interfaces\SubscriptionRepositoryInterface;
use App\Interfaces\SubscriptionTransactionRepositoryInterface;
use App\Interfaces\UserRepositoryInterface;
use App\Interfaces\PlanRepositoryInterface;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Validator;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Mail;
use App\Mail\PaymentSuccess;
use App\Mail\SubscriptionRenewed;
use App\Mail\SubscriptionReminder;
use App\Mail\SubscriptionFailed;
use App\Mail\NewAccount;

class SubscriptionController extends Controller
{
    private SubscriptionRepositoryInterface $subscriptionRepository;
    private SubscriptionTransactionRepositoryInterface $subscriptionTransactionRepository;
    private PlanRepositoryInterface $planRepository;
    private UserRepositoryInterface $userRepository;
    private OrganisationRepositoryInterface $organisationRepository;
    public function __construct(SubscriptionRepositoryInterface $subscriptionRepository, SubscriptionTransactionRepositoryInterface $subscriptionTransactionRepository, PlanRepositoryInterface $planRepository, UserRepositoryInterface $userRepository, OrganisationRepositoryInterface $organisationRepository)
    {
        $this->subscriptionRepository = $subscriptionRepository;
        $this->subscriptionTransactionRepository = $subscriptionTransactionRepository;
        $this->planRepository = $planRepository;
        $this->userRepository = $userRepository;
        $this->organisationRepository = $organisationRepository;
        $this->middleware("auth:api", ['except' => ['verifyPayment']]);
    }


    //Create New Subscription
    public function initateNewSubscription(Request $request)
    {
        try {
            //Check if user is superAdmin
            $user = Auth::user();
            $adminUser = $this->userRepository->checkIfAdmin($user->id);


            //Check If Plan Exists
            $plan = $this->planRepository->findById($request->plan_id);
            if (!$plan) {
                return response()->json([
                    'status' => 'failed',
                    'message' => 'Plan does not exist',
                ], 400);
            }

            //Check If user is cleared to make transactions
            if ($user->is_active != 1) {
                return response()->json([
                    'status' => 'failed',
                    'message' => 'Account limited from making subcriptions, Contact Support',
                ], 400);
            }

            //Create Base Data In Tables
            // Calculate the start date (current timestamp)
            $startDate = Carbon::now();

            $subData = [
                "plan_id" => $plan->id,
                "subscription_duration" => $plan->bill_period,
                "status" => 'pending',
                "amount" => $plan->amount,
                "organisation_id" => $user->organisation_id,
                "is_active" => false
            ];
            $subscription = $this->subscriptionRepository->createSubscription($subData);

            //Generate & Send CheckOut URL
            $secret = env('PAYSTACK_SECRET');
            $baseUrl = env("PAYSTACK_URL");
            $url = "{$baseUrl}/transaction/initialize";
            $authorization = "Bearer {$secret}";
            $transactionRef = Str::random(16);
            $data = [
                "email" => $user->email,
                "amount" => $plan->amount * 100,
                "reference" => $transactionRef,
                "channels" => ["card"],
                "callback_url" => $request->callback_url
            ];
            $response = Http::withHeaders([
                'Authorization' => $authorization,
            ])->post($url, $data);
            $responseData = $response->json();

            $transactionData = [
                "organisation_id" => $user->organisation_id,
                "amount" => $plan->amount,
                "date_paid" => $startDate,
                "status" => 'pending',
                'payment_gateway' => $request->gateway,
                'currency' => $plan->currency,
                'reference_id' => $transactionRef,
                'type' => 'credit',
                "subscription_id" => $subscription->id,
                "email" => $user->email,
            ];

            $transaction = $this->subscriptionTransactionRepository->create($transactionData);

            return response()->json([
                'status' => 'success',
                'message' => 'Payment Initialized successfully',
                'data' => [
                    "checkout_url" => $responseData['data']['authorization_url'],
                    "reference" => $responseData['data']["reference"],
                ]
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'status' => 'failed',
                'message' => $e->getMessage(),
                'data' => []
            ], 500);
        }
    }

    //Manual Subscription
    public function manualInitateNewSubscription(Request $request)
    {
        try {
            //Check if user is superAdmin
            $user = Auth::user();
            $adminUser = $this->userRepository->checkIfAdmin($user->id);


            //Check If Plan Exists
            $plan = $this->planRepository->findById($request->plan_id);
            if (!$plan) {
                return response()->json([
                    'status' => 'failed',
                    'message' => 'Plan does not exist',
                ], 400);
            }

            //Check If user is cleared to make transactions
            if ($user->is_active != 1) {
                return response()->json([
                    'status' => 'failed',
                    'message' => 'Account limited from making subcriptions, Contact Support',
                ], 400);
            }

            //Create Base Data In Tables
            // Calculate the start date (current timestamp)
            $startDate = Carbon::now();

            $subData = [
                "plan_id" => $plan->id,
                "subscription_duration" => $plan->bill_period,
                "status" => 'completed',
                "amount" => $plan->amount,
                "organisation_id" => $user->organisation_id,
                "is_active" => true
            ];
            $subscription = $this->subscriptionRepository->createSubscription($subData);
            $updateOrganisation = $this->organisationRepository->update($user->organisation_id, ['plan_id' => $subscription->plan_id, 'subscription_id' => $subscription->id]);
            $transactionRef = Str::random(16);


            $transactionData = [
                "organisation_id" => $user->organisation_id,
                "amount" => $plan->amount,
                "date_paid" => $startDate,
                "status" => 'completed',
                'payment_gateway' => $request->gateway,
                'currency' => $plan->currency,
                'reference_id' => $transactionRef,
                'type' => 'credit',
                "subscription_id" => $subscription->id,
                "email" => $user->email,
            ];

            $transaction = $this->subscriptionTransactionRepository->create($transactionData);

            //Send Mail 
            $profile = $this->userRepository->getUserProfileByUser($user->id);

            //Send Email
            $mailData = [
                "name" => $profile->first_name . ' ' . $profile->last_name,
            ];
            Mail::to($user->email)->send(new NewAccount($mailData));

            return response()->json([
                'status' => 'success',
                'message' => 'Payment Initialized successfully',
                'data' => []
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'status' => 'failed',
                'message' => $e->getMessage(),
                'data' => []
            ], 500);
        }
    }

    //Lists all subscriptions
    public function listAll(Request $request)
    {
        try {
            //Check if user is superAdmin
            $user = Auth::user();
            $adminUser = $this->userRepository->checkIfAdmin($user->id);

            //Check If user is cleared to make transactions
            if ($user->is_active != 1) {
                return response()->json([
                    'status' => 'failed',
                    'message' => 'Account limited from making subcriptions, Contact Support',
                ], 400);
            }

            $subscriptions = $this->subscriptionRepository->listSubscriptions($user->organisation_id);
            return response()->json([
                'status' => 'success',
                'message' => 'Subcriptions retrieved successfully',
                'data' => $subscriptions
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'status' => 'failed',
                'message' => $e->getMessage(),
                'data' => []
            ], 500);
        }
    }

    //Get Data for Single Subscripitions
    public function getSubscription(Request $request)
    {
        try {

            //Check if user is admin
            $user = Auth::user();
            $adminUser = $this->userRepository->checkIfAdmin($user->id);

            //Check If user is cleared to make transactions
            if ($user->is_active != 1) {
                return response()->json([
                    'status' => 'failed',
                    'message' => 'Account limited from making subcriptions, Contact Support',
                ], 400);
            }

            $subscriptionId = $request->subcription_id;
            $subcription = $this->subscriptionRepository->getSubscription($subscriptionId);
            return response()->json([
                'status' => 'success',
                'message' => 'Plan retrieved successfully',
                'data' => $subcription
            ]);


        } catch (\Exception $e) {
            return response()->json([
                'status' => 'failed',
                'message' => $e->getMessage(),
                'data' => []
            ], 500);
        }
    }

    //Get Active Subscription
    public function getActiveSubscription()
    {
        try {
            $user = Auth::user();
            $adminUser = $this->userRepository->checkIfAdmin($user->id);

            $organisationId = $user->organisation_id;
            $subscription = $this->subscriptionRepository->getActiveSubscription($organisationId);

            return response()->json([
                'status' => 'success',
                'message' => 'Subscription retrieved successfully',
                'data' => $subscription
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'status' => 'failed',
                'message' => $e->getMessage(),
                'data' => []
            ], 500);
        }
    }

    //Validate Subcribtion Payment - For Initail Subscription

    public function verifyPayment(Request $request)
    {
        try {
            $reference = $request->reference;
            //Add Validations
            $validator = Validator::make(['reference' => $reference], [
                'reference' => 'required|string',
            ]);

            // Check if validation fails
            if ($validator->fails()) {
                return response()->json([
                    'status' => 'failed',
                    'message' => $validator->errors()->first(),
                ], 422);
            }

            $secret = env('PAYSTACK_SECRET');
            $baseUrl = env("PAYSTACK_URL");
            $url = "{$baseUrl}/transaction/verify/{$reference}";
            $authorization = "Bearer {$secret}";
            $response = Http::withHeaders([
                'Authorization' => $authorization,
            ])->get($url);
            $responseData = $response->json();

            //Handle App Changes Based on Verification
            if (!isset($responseData['status'])) {
                return response()->json([
                    'status' => 'failed',
                    'message' => 'Payment Verfication Failed',
                ], 400);
            }

            if ($responseData['data']['status'] == 'success') {
                //List Out Neccessry operations table
                $transaction = $this->subscriptionTransactionRepository->findByRef($reference);
                $subscription = $this->subscriptionRepository->getSubscription($transaction->subscription_id);
                $plan = $this->planRepository->findById(intval($subscription->plan_id));
                $user = Auth::user();


                //Confirm if amount paid matches plan amount
                $amountSettled = $responseData['data']['amount'] / 100;
                if ($amountSettled < $plan->amount) {
                    return response()->json([
                        'status' => 'failed',
                        'message' => 'Payment Verfication Failed - Part Payment, Contact Support!',
                    ], 400);
                }

                //Update Neccessary Tables and release value

                //Calculate the start date (current timestamp)
                $startDate = Carbon::now();

                //Calculate the end date which is one month from the start date
                $endDate = $startDate->copy()->addMonth();

                //Set the time of the end date to the end of the day (23:59:59)
                $endDate = $endDate->endOfDay();

                $dateSettled = date('Y-m-d H:i:s', strtotime($responseData['data']['paidAt']));

                $card_info = json_encode($responseData['data']['authorization']) ?? null;
                $transactionData = [
                    "fee" => $responseData['data']['fees'],
                    "date_settled" => $dateSettled,
                    "amount_settled" => $amountSettled,
                    "status" => "completed",
                    "card_info" => $card_info,
                    "email" => $responseData['data']['customer']['email'] ?? null
                ];

                $subscriptionData = [
                    "next_billing_date" => $endDate,
                    "start_date" => $startDate,
                    "end_date" => $endDate,
                    "is_active" => true,
                    "status" => 'completed'
                ];
                $updatedTransaction = $this->subscriptionTransactionRepository->update($transactionData, $transaction->id);
                $updateOrg = $this->organisationRepository->update($user->organisation_id, ['plan_id' => $subscription->plan_id, 'subscription_id' => $subscription->id]);
                $updatedSubscription = $this->subscriptionRepository->updateSubscription($subscription->id, $subscriptionData);

                return response()->json([
                    'status' => 'success',
                    'message' => 'Payment verified, and subsciption activiated successfully!',
                    'data' => $updatedSubscription
                ]);
            } else if ($responseData['data']['status'] == 'failed') {
                return response()->json([
                    'status' => 'failed',
                    'message' => 'Payment not completed',
                    'data' => [],
                ], 400);
            }
        } catch (\Exception $e) {
            return response()->json([
                'status' => 'failed',
                'message' => $e->getMessage(),
                'data' => []
            ], 500);
        }
    }

    public function deleteCard(Request $request)
    {
        try {
            $user = Auth::user();
            $org = $this->organisationRepository->findById($user->organisation_id);

            if (!$org && $org->is_active === false) {

                return response()->json([
                    'status' => 'failed',
                    'message' => 'You cannot add permissions at the moment',
                ], 400);
            }

            //Get Most Recent Transaction
            $subscription = $this->subscriptionRepository->getActiveSubscription($org->id);
            $transaction = $this->subscriptionTransactionRepository->findBySubscription($subscription->id);

            //Delete the card Info
            $revisedTransaction = $this->subscriptionTransactionRepository->deleteCard($transaction->id);

            return response()->json([
                'status' => 'success',
                'message' => 'Card deleted successfully!',
                'data' => $revisedTransaction
            ]);

        } catch (\Exception $e) {
            return response()->json([
                'status' => 'failed',
                'message' => $e->getMessage(),
                'data' => []
            ], 500);
        }
    }

    public function updateCard(Request $request)
    {
        try {
            $user = Auth::user();
            //Generate & Send CheckOut URL
            $secret = env('PAYSTACK_SECRET');
            $baseUrl = env("PAYSTACK_URL");
            $url = "{$baseUrl}/transaction/initialize";
            $authorization = "Bearer {$secret}";
            $transactionRef = Str::random(16);
            $data = [
                "email" => $user->email,
                "amount" => 50 * 100,
                "reference" => $transactionRef,
                "channels" => ["card"],
                "callback_url" => $request->callback_url
            ];
            $response = Http::withHeaders([
                'Authorization' => $authorization,
            ])->post($url, $data);
            $responseData = $response->json();
            if (isset($responseData['data'])) {
                return response()->json([
                    'status' => 'success',
                    'message' => 'Update Initialized successfully',
                    'data' => [
                        "checkout_url" => $responseData['data']['authorization_url'],
                        "reference" => $responseData['data']["reference"],
                    ]
                ]);
            } else {
                return response()->json([
                    'status' => 'failed',
                    'message' => "Something went wrong",
                    'data' => $responseData
                ], 500);
            }
        } catch (\Exception $e) {
            return response()->json([
                'status' => 'failed',
                'message' => $e->getMessage(),
                'data' => []
            ], 500);
        }
    }

    public function verifyCardUpdate(Request $request)
    {
        try {
            $reference = $request->reference;
            //Add Validations
            $validator = Validator::make(['reference' => $reference], [
                'reference' => 'required|string',
            ]);

            // Check if validation fails
            if ($validator->fails()) {
                return response()->json([
                    'status' => 'failed',
                    'message' => $validator->errors()->first(),
                ], 422);
            }

            $user = Auth::user();
            $org = $this->organisationRepository->findById($user->organisation_id);

            $secret = env('PAYSTACK_SECRET');
            $baseUrl = env("PAYSTACK_URL");
            $url = "{$baseUrl}/transaction/verify/{$reference}";
            $authorization = "Bearer {$secret}";
            $response = Http::withHeaders([
                'Authorization' => $authorization,
            ])->get($url);
            $responseData = $response->json();

            //Handle App Changes Based on Verification
            if (!isset($responseData['status'])) {
                return response()->json([
                    'status' => 'failed',
                    'message' => 'Payment Verfication Failed',
                ], 400);
            }

            if ($responseData['data']['status'] == 'success') {
                //Get Most Recent Transaction
                $subscription = $this->subscriptionRepository->getActiveSubscription($org->id);
                $transaction = $this->subscriptionTransactionRepository->findBySubscription($subscription->id);

                $card_info = json_encode($responseData['data']['authorization']) ?? null;
                $dateSettled = date('Y-m-d H:i:s', strtotime($responseData['data']['paidAt']));
                $amountSettled = $responseData['data']['amount'] / 100;

                //Update Only Card Info
                $transactionData = [
                    "card_info" => $card_info,
                    "email" => $responseData['data']['customer']['email'] ?? null
                ];

                //Update with new card info
                $updatedTransaction = $this->subscriptionTransactionRepository->update($transactionData, $transaction->id);
                $newCardInfo = $this->subscriptionTransactionRepository->updateCard($transaction->id);

                //Send Refund

                return response()->json([
                    'status' => 'success',
                    'message' => 'Payment verified, and card updated!',
                    'data' => $updatedTransaction
                ]);
            } else if ($responseData['data']['status'] == 'failed') {
                return response()->json([
                    'status' => 'failed',
                    'message' => 'Card could not be updated',
                    'data' => [],
                ], 400);
            }
        } catch (\Exception $e) {
            return response()->json([
                'status' => 'failed',
                'message' => $e->getMessage(),
                'data' => []
            ], 500);
        }
    }

}