<?php

namespace App\Http\Helpers;

use App\Models\BillingData;
use App\Models\Milestone;
use App\Models\MuhandisinsProfit;
use App\Models\Proposal;
use App\Models\ServiceOrder;
use App\Models\StripeError;
use App\Models\Transaction;
use App\Models\Wallet;
use App\Notifications\PaymentVerified;
use Exception;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Session;
use Inertia\Inertia;
use Stripe\Account;
use Stripe\Exception\ApiErrorException;

class StripeClient
{

    public static function setAccountInterival(string $accountId, string $interval)
    {
        try {
            return StripeClient::stripe()->accounts->update($accountId,
                ['settings' => ['payouts' => ['schedule' => ['interval' => $interval]]]]
            );
        } catch(\Stripe\Exception\CardException|\Stripe\Exception\ApiErrorException| \Stripe\Exception\InvalidRequestException $e) {

            StripeError::create([
                'user_id'=>Auth::user()->id,
                'error_message'=>$e->getMessage(),
                'error_code'=>$e->getCode(),
                'stripe_url'=> $e->getError()->request_log_url,
            ]);
            throw $e;
        }   catch (Exception $e) {
            throw $e;
        }
    }

    public static function stripe(?bool $prod=false): \Stripe\StripeClient
    {
        $key = (string)env(env('STRIPE_MODE')==='PROD'? 'STRIPE_SECRET_PROD': 'STRIPE_SECRET');
        return new \Stripe\StripeClient($key);
    }

    public static function createAccount($entity,$country,$city,$address1)
    {
        try {
//            foreach (StripeClient::stripe()->accounts->all() as $acc){
//                self::stripe()->accounts->delete($acc->id);
//            }
            //dd(explode(' ',$entity->location->address),$entity->location);
            $data = [
                'email'=>$entity->email,
                'business_type' => 'individual',
                'type' => "express",
                'capabilities'=>['transfers' => ['requested' => true]],
                'tos_acceptance'=> ['service_agreement' => $country!='US'? 'recipient':'full',],
                'country'=> $country,
                'individual'=>[
                  'address'=> [
                      'city'=>$city,
                      'line1'=>$address1,
                      'country'=>$country,
                  ],
                ],
                'settings' => ['payouts' => ['schedule' => ['interval' => 'manual']]],
            ];

                $account= StripeClient::stripe()->accounts->create($data);

                $entity->billingAccounts()->create(
                    [
                        'stripe_id'=>$account->id,
                    ]
                );
//            dd($account->id,$entity->billingAccounts,self::stripe()->accounts->retrieve($account->id)->details_submitted);
            if(!self::stripe()->accounts->retrieve($account->id)->details_submitted){
                $accountLink= StripeClient::stripe()->accountLinks->create([
                    'account'=>$account->id,
                    'type'=>'account_onboarding',
                    'refresh_url'=> env('APP_URL')  .'/u/create-connected-account',
                    'return_url'=> env('APP_URL') . '/u/wallet'
                ]);
//            dd($accountLink);
                return $accountLink->url;
            }else{
                $accountLink= StripeClient::stripe()->accountLinks->create([
                    'account'=>$account->id,
                    'type'=>'account_update',
                    'refresh_url'=> env('APP_URL')  .'/u/wallet',
                    'return_url'=> env('APP_URL') . '/u/wallet'
                ]);
//            dd($accountLink);
                return $accountLink->url;
            }
            // add an error to the session

            return route('user.wallet');


        } catch(\Stripe\Exception\CardException|\Stripe\Exception\ApiErrorException| \Stripe\Exception\InvalidRequestException $e) {

            StripeError::create([
                'user_id'=>Auth::user()->id,
                'error_message'=>$e->getMessage(),
                'error_code'=>$e->getCode(),
                'stripe_url'=> $e->getError()->request_log_url,
            ]);
            throw $e;
        }   catch (Exception $e) {
            throw $e;
        }
    }

    public static function updateAccount($accountId){
        try{

                $accountLink= StripeClient::stripe()->accountLinks->create([
                    'account'=>$accountId,
                    'type'=>'account_onboarding',
                    'refresh_url'=> env('APP_URL')  .'/u/wallet',
                    'return_url'=> env('APP_URL') . '/u/wallet'
                ]);
                return $accountLink->url;

        }catch(\Stripe\Exception\CardException|\Stripe\Exception\ApiErrorException| \Stripe\Exception\InvalidRequestException $e) {

            StripeError::create([
                'user_id'=>Auth::user()->id,
                'error_message'=>$e->getMessage(),
                'error_code'=>$e->getCode(),
                'stripe_url'=> $e->getError()->request_log_url,
            ]);
            throw $e;
        }   catch (Exception $e) {

            throw $e;
        }

    }

    public static function deleteConnectedAccount($accountId){
        try{
            self::stripe()->accounts->delete($accountId);
        }catch(\Stripe\Exception\CardException|\Stripe\Exception\ApiErrorException| \Stripe\Exception\InvalidRequestException $e) {

            StripeError::create([
                'user_id'=>Auth::user()->id,
                'error_message'=>$e->getMessage(),
                'error_code'=>$e->getCode(),
                'stripe_url'=> $e->getError()->request_log_url,
            ]);
            throw $e;
        }   catch (Exception $e) {
            throw $e;
        }
    }
    public static function payout(array $data, $accountId)
    {
        $transfer=null;
        $payout=null;
        try {
//            $account = self::stripe()->accounts->retrieve($accountId);
//            dd($account);
//            dd($data);
            $data['currency'] = self::stripe()->accounts->retrieveExternalAccount($accountId,$data['destination'])->currency;
//            dd($data);
            $transfer = self::stripe()->transfers->create(
                [
                    'amount' => $data['amount']-200,
                    'destination'=> $accountId,
                    'currency'=>'usd',
                ]
            );
//            dd($transfer);
            $balance = self::stripe()->balance->retrieve([], ['stripe_account' => $accountId]);
//            dd($balance->available, $balance->pending);
//            $data['source_type']='card';
            if($balance->available[0]['amount']>=0){
                $data['amount']=$balance->available[0]['amount'];
                $data['currency']=$balance->available[0]['currency'];

//            dd($data);
                $payout = StripeClient::stripe()->payouts->create($data, [
                    'stripe_account' => $accountId,
                ]);
                return $payout;
            }
            throw ApiErrorException::factory('invalid balance');

        } catch(\Stripe\Exception\CardException|\Stripe\Exception\ApiErrorException| \Stripe\Exception\InvalidRequestException $e) {
            if($transfer!=null && $payout==null){
                self::stripe()->transfers->createReversal($transfer->id,[]);
            }
            StripeError::create([
                'user_id'=>Auth::user()->id,
                'error_message'=>$e->getMessage(),
                'error_code'=>$e->getCode(),
                'stripe_url'=> $e->getError()->request_log_url,
            ]);
            throw $e;
        }   catch (Exception $e) {
            throw $e;
        }
    }

    public static function addBankAccount(string $accountId, array $data)
    {
        try {
            return StripeClient::stripe(false)->accounts->createExternalAccount($accountId, $data);
        } catch(\Stripe\Exception\CardException|\Stripe\Exception\ApiErrorException| \Stripe\Exception\InvalidRequestException $e) {

            StripeError::create([
                'user_id'=>Auth::user()->id,
                'error_message'=>$e->getMessage(),
                'error_code'=>$e->getCode(),
                'stripe_url'=> $e->getError()->request_log_url,
            ]);
            throw $e;
        }   catch (Exception $e) {
            throw $e;
        }

    }

    public static function addCard(string $accountId, array $data)
    {
        try {
            return dd(StripeClient::stripe(false)->accounts->createExternalAccount($accountId, $data));
        } catch(\Stripe\Exception\CardException|\Stripe\Exception\ApiErrorException| \Stripe\Exception\InvalidRequestException $e) {

            StripeError::create([
                'user_id'=>Auth::user()->id,
                'error_message'=>$e->getMessage(),
                'error_code'=>$e->getCode(),
                'stripe_url'=> $e->getError()->request_log_url,
            ]);
            throw $e;
        }   catch (Exception $e) {
            throw $e;
        }

    }

    public static function charge(array $data)
    {
        try {
            return self::stripe()->charges->create($data);

        } catch(\Stripe\Exception\CardException|\Stripe\Exception\ApiErrorException| \Stripe\Exception\InvalidRequestException $e) {

            StripeError::create([
                'user_id'=>Auth::user()->id,
                'error_message'=>$e->getMessage(),
                'error_code'=>$e->getCode(),
                'stripe_url'=> $e->getError()->request_log_url,
            ]);
            throw $e;
        }   catch (Exception $e) {
            throw $e;
        }

    }

    public static function createPaymentIntent(array $data)
    {
        try {
            $data['automatic_payment_methods'] = ['enabled' => true];
            $data['currency'] = 'usd';
            return StripeClient::stripe()->paymentIntents->create($data);
        } catch(\Stripe\Exception\CardException|\Stripe\Exception\ApiErrorException| \Stripe\Exception\InvalidRequestException $e) {
            StripeError::create([
                'user_id'=>Auth::user()->id,
                'error_message'=>$e->getMessage(),
                'error_code'=>$e->getCode(),
                'stripe_url'=> $e->getError()->request_log_url,
            ]);
            throw $e;
        }   catch (Exception $e) {
            throw $e;
        }
    }

    public static function confirmPayment(string $id)
    {
        if(Transaction::where('stripe_id',$id)->get()->first()!=null){
            session()->flash('error', "Can't access this page");
            return redirect(url('/c/dashboard'));
        }
        try {
            $dbtransaction = DB::transaction(function () use ($id) {
                $intent = StripeClient::stripe()->checkout->sessions->retrieve($id);
                // Log the payment intent
                logger('payment intent', ['intent' => $intent]);

                // dd($intent);

                // dd($intent->metadata['muh_client_signature']);


                if ($intent->payment_status == "paid") {
                    $milestone= Milestone::findOrFail($intent->metadata['milestone_id']);
                    $transaction = [
                        'amount' => $milestone->amount,
                        'type' => 'Payment',
                        'from' => $intent->metadata['from'],
                        "to" => $intent->metadata['to'],
                        'status' => 'reserved',
                        'milestone_id' => $intent->metadata['milestone_id'],
                        'stripe_id' => $intent->id,
                        'stripe_type' => $intent->object,
                        'stripe_data' => json_encode($intent),
                    ];

                    $milestone->status = 'paid';
                    $milestone->due_date =
                    $milestone->save();
                    if($intent->metadata['muh_client_signature']!=null){
                        //
                      $proposal= $milestone->milestonable;
                      if(get_class($proposal)  == 'App\Models\Proposal') {
                          $proposal->confirmPayment([
                              'client_signature' => $intent->metadata['muh_client_signature'],
                          ]);
                      }else{
                          $proposal->client_signature = $intent->metadata['muh_client_signature'];
                          $proposal->save();
                      }
                    }

                    $transaction = Transaction::create($transaction);
                    $transaction->updateWalletsOnPayment($intent);


                    // Log the transaction
                    logger('transaction', ['transaction' => $transaction]);
                }
            });
            return is_null($dbtransaction)
                ?
                   Inertia::render("Payments/Success", [
                    "session_id" => $id,
                    // need to get the redirect url from the session_id
                    "redirect_to" => 'client.dashboard',
                ])
                : $dbtransaction;
        } catch(\Stripe\Exception\CardException|\Stripe\Exception\ApiErrorException| \Stripe\Exception\InvalidRequestException $e) {

            StripeError::create([
                'user_id'=>Auth::user()->id,
                'error_message'=>$e->getMessage(),
                'error_code'=>$e->getCode(),
                'stripe_url'=> $e->getError()->request_log_url,
            ]);
            throw $e;
        }   catch (Exception $e) {
            throw $e;
        }
    }

    public static function createPaymentSession(array $data)
    {
        try {
            $data['mode'] = 'payment';
            $data['success_url'] = env('APP_URL') . '/payment/success?session_id={CHECKOUT_SESSION_ID}';
            $data['cancel_url'] = url()->previous();


            $session = StripeClient::stripe()->checkout->sessions->create($data);

            return $session;

        } catch(\Stripe\Exception\CardException|\Stripe\Exception\ApiErrorException| \Stripe\Exception\InvalidRequestException $e) {

            StripeError::create([
                'user_id'=>Auth::user()->id,
                'error_message'=>$e->getMessage(),
                'error_code'=>$e->getCode(),
                'stripe_url'=> $e->getError()->request_log_url,
            ]);
            throw $e;
        }   catch (Exception $e) {
            throw $e;
        }
    }


}
