<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Customer\CustomerFrontController;
use App\Jobs\ClientSyncJobForSingle;
use App\Models\BillGenerate;
use App\Models\Billpayment;
use App\Models\Client;
use App\Models\CustomerAccount;
use App\Models\Packages;
use Brian2694\Toastr\Facades\Toastr;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;


class SurjoPayController extends Controller
{
    private $username;
    private $password;
    private $baseUrl;
    private $generatedToken;
    private $return_url;
    private $cancelUrl;
    private $prefix;
    private $store_id;
    private $customer_name;
    private $customer_phone;
    private $amount_topay;
    private $orderId;
    private $currency;
    private $customer_email;
    private $customerAddress;
    private $customerRoadNo;
    private $customerCity;
    private $customerDistrict;
    private $customerThana;
    private $customer_ip;
    private $checkout_url;
    private $sp_order_id;
    private $callBackUrl;
    private $customer_id;


    public function __construct()
    {
        $this->username = env('SURJO_USER_NAME');
        $this->password = env('SURJO_PASSCODE');
        // SURJOPAY_BASE_URL example:
        // Sandbox:    https://sandbox.shurjopayment.com/api
        // Production: https://engine.shurjopayment.com/api
        $this->baseUrl = rtrim(env('SURJOPAY_BASE_URL'), '/');
        $this->prefix = env('SURJO_PREFIX');
        $this->return_url = env('SURJO_RETURN_URL');
        $this->cancelUrl = env('SURJO_CANCEL_URL');
        $this->callBackUrl = env('SURJO_CALLBACK_URL');
    }

    public function getClientInformation(Request $request)
    {
        $customerData = CustomerFrontController::getClientInfo($request);

        // Ensure we have a valid customer object from CustomerFrontController::getClientInfo
        if (!is_array($customerData) || empty($customerData['clientlist'])) {
            return;
        }

        $customer_info = $customerData['clientlist'];

        session(['customer_id' => $customer_info->id]);
        $customerBillingInfo = $customer_info->clientsinfo;

        if ($customerBillingInfo->clients_name !== null) {
            $this->customer_name = trim($customerBillingInfo->clients_name);
        } else {
            $this->customer_name = trim(env('SURJO_CUSTOMER_NAME'));
        }

        if ($customerBillingInfo->contact_no !== null) {
            $this->customer_phone = $customerBillingInfo->contact_no;
        } else {
            $this->customer_phone = env('SURJO_DEFAULT_PHONE');
        }

        if ($customerBillingInfo->email !== null) {
            $this->customer_email = $customerBillingInfo->email;
        } else {
            $this->customer_email = env('SURJO_DEFAULT_EMAIL');
        }

        if ($customerBillingInfo->road_no !== null) {
            $this->customerRoadNo = $customerBillingInfo->road_no;
        } else {
            $this->customerRoadNo = env('SURJO_ROADNO');
        }

        $this->currency = env('SURJO_CURRENCY');

        if ($customer_info != null) {
            $id                     = $customer_info->id;
            $details['userinfo']    =  $customer_info;
            $details['paymentinfo'] = Billpayment::whereClient_id($id)->get();
            $details['billinginfo'] = BillGenerate::whereClient_id($id)->get();
            $details['package']     = Packages::where('id', $customer_info->package_id)->first();
            $details['account']     = CustomerAccount::firstOrCreate(['client_id' => $id]);

            $bill_amount = 0;

            if ($details['account']->dueAmount > 0) {
                $bill_amount = $details['account']->dueAmount;
            } else {
                $bill_amount = $details['package']->package_rate + $details['account']->dueAmount;
            }

            $this->amount_topay = (float)$bill_amount;
        }

        $district = DB::table('districts')->where('id', $customerBillingInfo->district)->get();
        $thana = DB::table('upazilas')->where('id', $customerBillingInfo->thana)->get();
        $divison = DB::table('divisions')->where('id', $customerBillingInfo->division)->get();

        if ($divison != null && $divison != '') {
        }
        /*address*/

        if ($divison != null && count($divison) != 0) {
            $this->customerCity = trim($divison[0]->name);
        } else {
            $this->customerCity = trim(env('SURJO_CITY'));
        }


        if ($district != null && count($district) != 0) {
            $this->customerDistrict = trim($district[0]->name);
        } else {
            $this->customerDistrict = trim(env('SURJO_CITY'));
        }


        if ($thana != null && count($thana) != 0) {
            $this->customerThana = trim($thana[0]->name);
        } else {
            $this->customerThana = trim(env('SURJO_THANA'));
        }

        $this->customerAddress = trim($this->customerRoadNo . " " . $this->customerThana . " " . $this->customerDistrict . " " . $this->customerCity);
        $this->customer_ip = $request->ip();

        $this->orderId = trim($customer_info->id . $this->customer_ip . $this->prefix . substr($this->customer_name, 0, 4) . substr($this->customer_phone, 0, 5) . date("Y-m-d", time()) . "time" . date("h:i:s") . "u_name" . trim($customer_info->userid));
    }


    private function requestToken()
    {
        $header = [
            "Accept" => "application/json",
            "Content-Type" => "application/json",
        ];

        $response = Http::withHeaders($header)->post("{$this->baseUrl}/get_token", [
            'username' => $this->username,
            'password' => $this->password,
        ]);

        if (!$response->successful()) {
            throw new \RuntimeException('Unable to generate SurjoPay token. HTTP status: ' . $response->status());
        }

        $data = $response->json();

        if (!is_array($data) || empty($data['token']) || empty($data['store_id'])) {
            throw new \RuntimeException('Invalid response received from SurjoPay token API.');
        }

        $this->generatedToken = $data['token'];
        $this->store_id = $data['store_id'];
    }

    public function generateToken(Request $request)
    {
        $this->requestToken();
        $this->getClientInformation($request);
    }

    public function executePayment(Request $request)
    {
        // Remember origin slug (for client-payment/{token} flows)
        if ($request->filled('slug')) {
            session(['surjo_origin_slug' => $request->slug]);
        } else {
            session()->forget('surjo_origin_slug');
        }

        $this->generateToken($request);

        $header = [
            "Authorization" => "Bearer $this->generatedToken",
            "Content-Type" => "application/json",
            "Accept" => "application/json"
        ];

        $body_json = [
            "token" => $this->generatedToken,
            "prefix" => $this->prefix,
            "return_url" => $this->callBackUrl . "/surjo-payment-callback",
            "cancel_url" => $this->cancelUrl,
            "store_id" => $this->store_id,
            "order_id" => $this->orderId,
            "amount" => $request->amount,
            "currency" => $this->currency,
            "customer_name" => $this->customer_name,
            "customer_address" => $this->customerAddress,
            "customer_email" => $this->customer_email,
            "customer_phone" => $this->customer_phone,
            "customer_city" => $this->customerCity,
            "client_ip" => $this->customer_ip,
        ];

        // shurjoPay REST API: POST {baseUrl}/secret-pay
        $response = Http::withHeaders($header)->post("{$this->baseUrl}/secret-pay", $body_json);

        session(['surjo_recharge_amount' => $request->amount]);

        $data = $response->json();

        if (
            !$response->successful() ||
            !is_array($data) ||
            empty($data['checkout_url']) ||
            empty($data['sp_order_id'])
        ) {
            throw new \RuntimeException('Invalid response from ShurjoPay checkout API.');
        }

        $this->checkout_url = $data['checkout_url'];
        $this->sp_order_id = $data['sp_order_id'];

        return $data['checkout_url'];
    }

    public function verifyPayment(Request $request)
    {
        $url = "{$this->baseUrl}/verification";
    }

    public function surjoPaymenCallback(Request $request)
    {
        $this->requestToken();
        $header = [
            "Authorization" => "Bearer $this->generatedToken",
            "Content-Type" => "application/json",
            "Accept" => "application/json"
        ];

        // REST API: verification endpoint
        $url = "{$this->baseUrl}/verification";
        $orderId = $request->order_id;
        $response_payment = Http::withHeaders($header)->post($url, ['order_id' => $orderId]);

        $resposnse = json_decode($response_payment->body(), true);

        if (($resposnse[0]['sp_code'] ?? null) == 1000 && $resposnse[0]['amount'] == session('surjo_recharge_amount')) {
            DB::beginTransaction();
            try {
                (new PaymentController)->surjoPayClientCheckOutPaymentProcess(
                    $resposnse[0]['amount'],
                    session('customer_id'),
                    $resposnse[0]['bank_trx_id'],
                    $resposnse[0]['phone_no'],
                    $orderId,
                    $resposnse[0]['date_time'],
                );
                DB::commit();
            } catch (\Exception $e) {
                DB::rollBack();
                Toastr::error('ShurjoPay Payment is not Successful');
                return redirect()->route('customerDashboard');
            }

            if (checkAPI()) {
                ClientSyncJobForSingle::dispatch(session('customer_id'));
            }

            Toastr::success('ShurjoPay Payment is Successful');
            $slug = session('surjo_origin_slug');
            if ($slug) {
                session()->forget('surjo_origin_slug');
                return redirect()->route('client-open-payment', $slug);
            }
            return redirect()->route('customerDashboard');
        } else {
            Toastr::error('ShurjoPay Payment is not Successful');
            return redirect()->route('customerDashboard');
        }
        Toastr::error('ShurjoPay Payment is not Successful');
        return redirect()->route('customerDashboard');
    }

    public function surjoPayIpn(Request $request)
    {
        // ShurjoPay IPN sends shurjoPay order_id (sp_order_id)
        $shurjoOrderId = $request->input('order_id');

        if (!$shurjoOrderId) {
            echo "Invalid Data";
            return;
        }

        // Step 1: verify payment using ShurjoPay verification API
        $this->requestToken();

        $header = [
            "Authorization" => "Bearer $this->generatedToken",
            "Content-Type" => "application/json",
            "Accept" => "application/json",
        ];

        $url = "{$this->baseUrl}/verification";
        $response_payment = Http::withHeaders($header)->post($url, ['order_id' => $shurjoOrderId]);

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

        if (!is_array($response) || empty($response[0])) {
            echo "Invalid Transaction";
            return;
        }

        $data = $response[0];

        // Extract our own customer/order reference from customer_order_id
        $customerOrderId = $data['customer_order_id'] ?? '';
        $customerId = null;
        if (preg_match('/^(\d+)/', (string) $customerOrderId, $matches)) {
            $customerId = (int) $matches[1];
        }

        if (($data['sp_code'] ?? null) == 1000) {
            // Successful transaction according to ShurjoPay
            if ($customerId) {
                DB::beginTransaction();
                try {
                    (new PaymentController)->surjoPayClientCheckOutPaymentProcess(
                        $data['amount'],
                        $customerId,
                        $data['bank_trx_id'] ?? null,
                        $data['phone_no'] ?? null,
                        $data['order_id'] ?? $shurjoOrderId,
                        $data['date_time'] ?? now()
                    );
                    DB::commit();
                } catch (\Exception $e) {
                    DB::rollBack();
                    echo "Payment processing failed";
                    return;
                }
            }

            echo "Transaction is successfully Completed";
        } else {
            echo "Invalid Transaction";
        }
    }

    public function surjoPaymentCancel(Request $request)
    {
        Toastr::error('ShurjoPay Payment was cancelled');
        return redirect()->route('customerDashboard');
    }
}
