<?php

namespace App\Repositories\Website;

use App\Models\Client;
use App\Models\Movie;
use App\Models\RentalHistory;
use App\Models\Subscription;
use App\Models\SubscriptionTransactionLog;
use App\Models\TvShow;
use App\Models\User;
use App\Repositories\Interfaces\Website\SubscriptionRepositoryInterface;
use Illuminate\Support\Facades\Auth;
use App\Traits\ImageTrait;
use Carbon\Carbon;
use Exception;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class SubscriptionRepository implements SubscriptionRepositoryInterface
{
    use ImageTrait;
    // 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']);
            $status = 0;

            if (isset($billingInfo['transaction_file'])) {
                if (isset($billingInfo['transaction_file']) && $billingInfo['transaction_file'] instanceof UploadedFile) {
                    $requestImage = $billingInfo['transaction_file'];
                    $response = $this->saveImage($requestImage, '_offline_payment_');
                    $file = $response['images'];
                }
            }
        }

        $client       = isset($plan['client_id']) ? Client::where('id', $plan['client_id'])->first() : Auth::user()->client;
        $is_recurring = 0;
        $expire_date  = now();

        if ($plan->type == 'monthly') {
            $expire_date  = now()->addDay($plan->day);
            $is_recurring = 1;
        }
        if ($plan->type == 'annually') {
            $expire_date  = now()->addDay($plan->day);
            $is_recurring = 1;
        }

        $subscription = Subscription::where('client_id', $client->id)->where('status', 1)->first();
        if ($subscription) {
            $subscription->status = 3;
            $subscription->save();
        }

        User::where('client_id', $client->id)->update(['subscription_id' => $plan->id]);

        $data         = [
            'client_id'         => $client->id,
            'plan_id'           => $plan->id ?? $plan['plan_id'],
            'is_recurring'      => $is_recurring,
            'status'            => $status,
            'purchase_date'     => now(),
            'expire_date'       => $expire_date,
            'price'             => $plan->price,
            'package_type'      => $plan->type,
            'profile_limit'     => $plan->screen,
            'post_limit'        => $plan->post_limit,
            'post_remaining'    => $plan->post_limit,
            'profile_remaining' => $plan->profile_limit,
            'team_limit'        => $plan->team_limit,
            'trx_id'            => $trx_id,
            'payment_method'    => $payment_method,
            'payment_details'   => isset($file) ? json_encode($file) : $payment_details,
            'client'            => Client::find($client->id),
            'subject'           => __('package_subscription_confirmation'),
        ];

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

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

        return Subscription::create($data);
    }

    public function cancelSubscription($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);
        }

        $subscription->canceled_at = now();
        $subscription->status      = 2;
        $log                       = SubscriptionTransactionLog::create([
            'description' => 'You cancel Your Subscription',
            'client_id'   => auth()->user()->client_id,
        ]);
        $subscription->save();

        return $subscription;
    }

    public function cancelStripe($subscription)
    {
        $stripe_subscript_id = getArrayValue('subscription', $subscription->payment_details);
        $response            = [];
        if ($stripe_subscript_id) {
            $headers  = [
                'Authorization' => 'Basic ' . base64_encode(setting('stripe_secret') . ':'),
                'Content-Type'  => 'application/x-www-form-urlencoded',
            ];

            $data     = [
                'invoice_now' => 'false',
            ];
            $response = httpRequest('https://api.stripe.com/v1/subscriptions/' . $stripe_subscript_id, $data, $headers, true, 'DELETE');
        }

        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 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 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 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]);

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

        return $subscribe->save();
    }

    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 == 'monthly') {
            $cancel_date  = $cancel_date->addDay();
        }
        if ($subscription->package_type == 'annually') {
            $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 rentVideo($request, $type)
    {
        try {

            if ($request['video_type'] == 'movie') {
                $video = Movie::where('id', $request['plan_id'])->first();
            } elseif ($request['video_type'] == 'series') {
                $video = TvShow::where('id', $request['plan_id'])->first();
            }

            if (isset($request['transaction_file'])) {
                if (isset($request['transaction_file']) && $request['transaction_file'] instanceof UploadedFile) {
                    $requestImage = $request['transaction_file'];
                    $response = $this->saveImage($requestImage, '_offline_payment_');
                    $file = $response['images'];
                }
            }

            $data = [
                'user_id'        => auth()->id() ?? $request['user_id'],
                'video_id'       => $video->id,
                'video_type'     => $request['video_type'],
                'transaction_id' => $request['transaction_key'] ?? $request['trx_id'],
                'price'          => $video->rental_price,
                'duration'       => $video->rental_duration,
                'type'           => $type,
                'file'           => isset($file) ? json_encode($file) : null,
                'status'         => ($type == 'offline') ? 0 : 1,
                'created_at'     => Carbon::now(),
                'updated_at'     => Carbon::now(),
            ];

            // Only insert if user+video doesn’t already exist
            return RentalHistory::firstOrCreate(
                [
                    'user_id' => $data['user_id'],
                    'video_id' => $data['video_id'],
                    'video_type' => $data['video_type'],
                ],
                $data
            );
        } catch (Exception) {
            return false;
        }
    }

    public function sslRedirect($request)
    {
        try {
            if ($request['video_type'] == 'movie') {
                $video = Movie::where('id', $request['video_id'])->first();
            } else {
                $video = TvShow::where('id', $request['video_id'])->first();
            }

            $post_data = [
                'store_id' => setting('ssl_store_id'),
                'store_passwd' => setting('ssl_store_password'),
                'total_amount' => $video['rental_price'],
                'currency' => 'BDT',
                'tran_id' => 'REF' . uniqid(),
                'success_url' => route('client.sslcommerce.success'),
                'fail_url' => route('client.sslcommerce.cancel'),
                'cancel_url' => route('client.sslcommerce.cancel'),

                'cus_name' => auth()->user()->first_name . ' ' . auth()->user()->last_name,
                'cus_email' => auth()->user()->email,
                'cus_add1' => 'Bangladesh',
                'cus_city' => 'City',
                'cus_country' => 'Bangladesh',
                'cus_phone' => auth()->user()->phone ?? 11111111111,

                'shipping_method' => 'NO',
                'product_name' => $video['title'],
                'product_category' => $request['video_type'],
                'product_profile' => $video['seo_title'],
                'value_a' => $request['video_type'],
                'value_b' => $video['id'],
                'value_c' => auth()->user()->id,
                'value_d' => $video['rental_duration'],
            ];

            if (setting('ssl_mode') == 'sandbox') {
                $url = "https://sandbox.sslcommerz.com/gwprocess/v4/api.php";
            } else {
                $url = "https://securepay.sslcommerz.com/gwprocess/v4/api.php";
            }

            $response = Http::asForm()->post($url, $post_data);
            $sslResponse = $response->json();

            return $sslResponse['GatewayPageURL'];
        } catch (Exception) {
            return false;
        }
    }

    public function sslSuccess($request)
    {
        try {
            $data = [
                'user_id'        => $request['value_c'],
                'video_id'       => $request['value_b'],
                'video_type'     => $request['value_a'],
                'transaction_id' => $request['val_id'],
                'price'          => $request['amount'],
                'duration'       => $request['value_d'],
                'type'           => 'SSLcommerz',
                'file'           => isset($file) ? json_encode($file) : null,
                'status'         => ($request['value_a'] == 'offline') ? 0 : 1,
                'created_at'     => Carbon::now(),
                'updated_at'     => Carbon::now(),
            ];
            // Only insert if user+video doesn’t already exist
            return RentalHistory::firstOrCreate(
                [
                    'user_id' => $data['user_id'],
                    'video_id' => $data['video_id'],
                    'video_type' => $data['video_type'],
                ],
                $data
            );
            return true;
        } catch (Exception) {
            return false;
        }
    }

    public function amarPayRedirect($request)
    {
        if ($request['video_type'] == 'movie') {
            $video = Movie::where('id', $request['video_id'])->first();
        } else {
            $video = TvShow::where('id', $request['video_id'])->first();
        }

        $storeId = setting('amarpay_store_id');
        $signatureKey = setting('amarpay_signature_key');

        // Trim to remove accidental newlines/spaces that cause header errors
        $storeId = is_string($storeId) ? trim($storeId) : $storeId;
        $signatureKey = is_string($signatureKey) ? trim($signatureKey) : $signatureKey;

        $payload = [
            'store_id'      => $storeId,
            'tran_id'       => uniqid('TXN_'),
            'success_url'   => route('client.aamarpay.success'),
            'fail_url'      => route('client.aamarpay.cancel'),
            'cancel_url'    => route('client.aamarpay.cancel'),
            'amount'        => $video['rental_price'],
            'currency'      => 'BDT',
            'signature_key' => $signatureKey,
            'desc'          => $video['title'],

            'cus_name'      => auth()->user()->first_name . ' ' . auth()->user()->last_name, // fixed concat + space
            'cus_email'     => auth()->user()->email,
            'cus_add1'      => 'House B-158 Road 22',
            'cus_add2'      => 'DOHS',
            'cus_city'      => 'Dhaka',
            'cus_state'     => 'Dhaka',
            'cus_postcode'  => '1206',
            'cus_country'   => 'Bangladesh',
            'cus_phone'     => auth()->user()->phone ?? '+8801704',
            'type'          => 'json',
            'opt_a'       => $request['video_type'],
            'opt_b'       => $video['id'],
            'opt_c'       => auth()->user()->id,
            'opt_d'       => $video['rental_duration'],
        ];

        $aamarpayEndpoint = setting('amarpay_mode') != 'sandbox'
            ? 'https://secure.aamarpay.com/jsonpost.php'
            : 'https://sandbox.aamarpay.com/jsonpost.php';

        try {
            $response = Http::withHeaders([
                'Content-Type' => 'application/json',
            ])->post($aamarpayEndpoint, $payload);
            // debug safely: log raw body + status + content-type

            // Try decoding JSON and check error
            $responseData = json_decode($response, true);

            if (!empty($responseData) && isset($responseData['result']) && $responseData['result'] == 'true') {
                return $responseData['payment_url'];
            }

            return false;
        } catch (Exception $e) {
            return false;
        }
    }

    public function amarPaySuccess($request)
    {
        try {
            $request_id = $request['mer_txnid']; // or 'tran_id' depending on your request field
            $pg_txnid = $request['pg_txnid']; // optional
            $storeId = setting('amarpay_store_id');
            $signatureKey = setting('amarpay_signature_key');

            // Trim to remove accidental newlines/spaces that cause header errors
            $storeId = is_string($storeId) ? trim($storeId) : $storeId;
            $signatureKey = is_string($signatureKey) ? trim($signatureKey) : $signatureKey;
            $type = 'json';

            // Prefer request_id (merchant txn id), fallback to pg_txnid
            $queryParam = $request_id ? "request_id={$request_id}" : "pg_txnid={$pg_txnid}";

            // Choose sandbox or live URL dynamically
            $aamarpayEndpoint = setting('amarpay_mode') != 'sandbox'
                ? 'https://secure.aamarpay.com/jsonpost.php'
                : 'https://sandbox.aamarpay.com/jsonpost.php';

            $url = "{$aamarpayEndpoint}?{$queryParam}&store_id={$storeId}&signature_key={$signatureKey}&type={$type}";

            // Make GET request using Laravel Http Client (recommended)
            $response = Http::get($url);
            $data = $response->json();

            if ($response->successful()) {
                $data = [
                    'user_id'        => $request['opt_c'],
                    'video_id'       => $request['opt_b'],
                    'video_type'     => $request['opt_a'],
                    'transaction_id' => $request['bank_txn'],
                    'price'          => $request['amount_original'],
                    'duration'       => $request['opt_d'],
                    'type'           => 'amar_pay',
                    'file'           => isset($file) ? json_encode($file) : null,
                    'status'         => ($request['opt_a'] == 'offline') ? 0 : 1,
                    'created_at'     => Carbon::now(),
                    'updated_at'     => Carbon::now(),
                ];

                return RentalHistory::firstOrCreate(
                    [
                        'user_id' => $data['user_id'],
                        'video_id' => $data['video_id'],
                        'video_type' => $data['video_type'],
                    ],
                    $data
                );
                return true;
            }
        } catch (Exception $e) {
            return false;
        }
    }

    public function paystackRedirect($request)
    {
        try {
            if ($request['video_type'] == 'movie') {
                $video = Movie::where('id', $request['video_id'])->first();
            } else {
                $video = TvShow::where('id', $request['video_id'])->first();
            }

            $metadata = [
                'user_id'    => auth()->id(),
                'video_id'   => $request['video_id'],
                'video_type' => $request['video_type'],
                'duration'   => $video['rental_duration'],
                'custom_note' => 'Payment for video access'
            ];

            $response = Http::withToken(setting('paystack_secret_key'))
                ->post('https://api.paystack.co/transaction/initialize', [
                    'email' => auth()->user()->email,
                    'amount' => $video['rental_price'] * 100, // amount in kobo
                    'callback_url' => route('client.paystack.callback'),
                    'metadata'     => $metadata,
                ]);

            $data = $response->json();

            if ($data['status']) {
                return $data['data']['authorization_url'];
            } else {
                return false;
            }
        } catch (\Exception) {
            return false;
        }
    }

    public function paystackCallback($request)
    {
        try {
            // ✅ 1. Get the payment reference
            $reference = $request['reference'] ?? null;

            if (!$reference) {
                return false;
            }

            // ✅ 2. Verify transaction via Paystack API
            $response = Http::withToken(setting('paystack_secret_key'))
                ->get("https://api.paystack.co/transaction/verify/{$reference}");

            $payment = $response->json();

            // ✅ 3. Check if response valid and successful
            if (!isset($payment['data']) || $payment['data']['status'] !== 'success') {
                return false;
            }

            $meta = $payment['data']['metadata'] ?? [];

            // ✅ 4. Prepare your data
            $data = [
                'user_id'        => $meta['user_id'] ?? null,
                'video_id'       => $meta['video_id'] ?? null,
                'video_type'     => $meta['video_type'] ?? null,
                'transaction_id' => $payment['data']['reference'], // 🔁 use reference, not ID
                'price'          => $payment['data']['amount'] / 100, // convert from kobo
                'duration'       => $meta['duration'] ?? null,
                'type'           => 'paystack',
                'file'           => isset($file) ? json_encode($file) : null,
                'status'         => 1, // ✅ success = 1
                'created_at'     => now(),
                'updated_at'     => now(),
            ];

            // ✅ 5. Save or update in RentalHistory
            RentalHistory::updateOrCreate(
                [
                    'user_id'    => $data['user_id'],
                    'video_id'   => $data['video_id'],
                    'video_type' => $data['video_type'],
                ],
                $data
            );

            return true;
        } catch (\Exception $e) {
            return false;
        }
    }

    public function mollieRedirect($request)
    {
        try {

            if ($request['video_type'] == 'movie') {
                $video = Movie::where('id', $request['video_id'])->first();
            } else {
                $video = TvShow::where('id', $request['video_id'])->first();
            }

            $orderId = 'tx_' . uniqid();
            $response = Http::withHeaders([
                'Authorization' => 'Bearer ' . setting('mollie_api_key'),
                'Content-Type' => 'application/x-www-form-urlencoded'
            ])->asForm()->post('https://api.mollie.com/v2/payments', [
                'amount[currency]' => 'EUR',
                'amount[value]' => number_format((float) $video['rental_price'], 2, '.', ''),
                'description' => 'Order #' . $orderId,
                'redirectUrl' => route('client.mollie.callback') . '?order=' . $orderId,
                'webhookUrl' => 'https://webshop.example.org/payments/webhook/',
                'metadata' => [
                    'order_id' => $orderId,
                    'user_id'    => auth()->id(),
                    'video_id'   => $request['video_id'],
                    'video_type' => $request['video_type'],
                    'duration'   => $video['rental_duration'],
                ],
            ]);

            $data = json_decode($response->body(), true);

            // create payment id on session
            session(['payment_id_' . $orderId => $data['id']]);

            if (isset($data['_links']['checkout']['href'])) {
                // Redirect user to Mollie checkout page
                return $data['_links']['checkout']['href'];
            } else {
                return false;
            }
        } catch (Exception) {
            return false;
        }
    }

    public function mollieCallback($request)
    {
        try {
            // The payment ID is returned by Mollie in the query string: ?id=tr_xxxxx
            $orderId = $request['order'];
            $paymentId = session('payment_id_' . $orderId);

            if (!$orderId) {
                return false;
            }

            // Fetch payment info from Mollie
            $response = Http::withHeaders([
                'Authorization' => 'Bearer test_cSKkJqnBJpteDkv6eSf9CfTDVe6Asq',
                'Content-Type' => 'application/json',
            ])->get("https://api.mollie.com/v2/payments/{$paymentId}");

            $payment = json_decode($response->body(), true);
            
            // Check if payment is paid
            if (isset($payment['status']) && $payment['status'] === 'paid') {

                $data = [
                    'user_id'        => $payment['metadata']['user_id'],
                    'video_id'       => $payment['metadata']['video_id'],
                    'video_type'     => $payment['metadata']['video_type'],
                    'transaction_id' => $payment['id'],
                    'price'          => $payment['amount']['value'],
                    'duration'       => $payment['metadata']['duration'],
                    'type'           => 'mollie',
                    'file'           => isset($file) ? json_encode($file) : null,
                    'status'         => ($payment['status'] == 'offline') ? 0 : 1,
                    'created_at'     => Carbon::now(),
                    'updated_at'     => Carbon::now(),
                ];
                return RentalHistory::firstOrCreate(
                    [
                        'user_id' => $data['user_id'],
                        'video_id' => $data['video_id'],
                        'video_type' => $data['video_type'],
                    ],
                    $data
                );
                return true;

                // empty payment id from session
                session(['payment_id_' . $orderId => null]);

                // Payment is successful
                return true;
            } else {
                return false;
            }
        } catch (Exception) {
            return false;
        }
    }
}
