<?php
require_once("./config/db_config.php");
require('sdk/stripe/init.php');
require_once('Logger.php');
class StripePaymentGateway
{
    public $domainURL;
    public $stripeClient;

    public function __construct($domainURL = domainURL)
    {
        $this->domainURL = $domainURL;     
    }

    /**
     * Create an order for Stripe payment and return the form
     *
     * @param array $paymentDetails Payment details (amount, email, etc.)
     * @param array $gatewayDetails Stripe gateway configuration (publicKey, secretKey, etc.)
     * @return string HTML form
     */
    public function createOrder($paymentDetails, $gatewayDetails)
    {
        $secretKey = $gatewayDetails['secretKey'];
        $publicKey = $gatewayDetails['publicKey'];
        $env = $gatewayDetails['env'];
        $currency = $gatewayDetails['currencyCode'];
        $amount = $paymentDetails['amount'] * 100; // Stripe uses amount in cents
        $returnurl = $this->domainURL . "/paymentResponse.php";
        $paymentType = isset($paymentDetails['paymentType'])?$paymentDetails['paymentType']:'';
        $onlinePaymentId = isset($paymentDetails['onlinePaymentId'])?$paymentDetails['onlinePaymentId']:'';
        $screenName = isset($paymentDetails['screenName'])?$paymentDetails['screenName']:'';
        \Stripe\Stripe::setApiKey($secretKey);
        // Return HTML for Stripe checkout button and hidden form data
        return $this->generateCheckoutForm($paymentDetails, $returnurl, $amount, $currency, $publicKey,$secretKey, $env,$paymentType,$onlinePaymentId,$screenName);
    }

    /**
     * Generates the HTML form for Stripe checkout
     *
     * @param array $paymentDetails
     * @param string $returnurl
     * @param int $amount
     * @param string $currency
     * @param string $publicKey
     * @param string $env
     * @return string HTML form
     */
    private function generateCheckoutForm($paymentDetails, $returnurl, $amount, $currency, $publicKey,$secretKey, $env,$paymentType,$onlinePaymentId,$screenName)
    {
        $form = <<<HTML
            <form action="{$returnurl}" method="post" name="checkout" id="checkout">
                <script src="{$env}"
                    class="stripe-button"
                    data-key="{$publicKey}"
                    data-amount="{$amount}"
                    data-email="{$paymentDetails['email']}"
                    data-name="{$paymentDetails['name']}"
                    data-description="Payment Description"
                    data-phone="{$paymentDetails['phoneNo']}"
                    data-currency="{$currency}">
                </script>
                <input type="hidden" name="amount" value="{$amount}"/>
                <input type="hidden" name="email" value="{$paymentDetails['email']}"/>
                <input type="hidden" name="name" value="{$paymentDetails['name']}"/>
                <input type="hidden" name="phone" value="{$paymentDetails['phoneNo']}"/>
                <input type="hidden" name="id" value="{$paymentDetails['id']}"/>
                <input type="hidden" name="onlinePaymentId" value="{$onlinePaymentId}"/>
                <input type="hidden" name="screenName" value="{$screenName}"/>
                <input type="hidden" name="paymentType" value="{$paymentType}"/>
                <input type="hidden" name="publicKey" value="{$publicKey}"/>
                <input type="hidden" name="secretKey" value="{$secretKey}"/>
            </form>
            <script type="text/javascript">
                
            if(document.getElementsByClassName('stripe-button-el').length > 0){
                document.getElementsByClassName('stripe-button-el')[0].style.display = 'none';
            }
                setTimeout(()=> {
                    document.getElementById("loader").style.display = 'none';
                    document.getElementsByClassName('stripe-button-el')[0].click()
                },2000)
            </script>
        HTML;
        return $form;
    }

    /**
     * Fetch order details after Stripe payment
     *
     * @param array $data Payment data
     * @return array Payment response
     */
    public function fetchOrder($data)
    {
        // Initialize response structure
        $response = $this->initializeresponse();

        try {
            if (empty($data['stripeData']['secretKey'])) {
                Logger::error("Stripe API key not provided.");
                $response['error'] = "Stripe API key not provided.";
                return $response;
            }
            $gatewayData = json_decode($data['gatewayConfig'] , true);
            $currencyCode = $gatewayData['currencyCode'];
            // Set the Stripe API secret key
            \Stripe\Stripe::setApiKey($data['stripeData']['secretKey']);
            // Create Stripe customer
            $customer = $this->createStripeCustomer($data['stripeData']);
            $charge = $this->processPayment($customer->id, $data['stripeData']['amount'], $currencyCode);

            // Handle successful charge
            if ($charge) {
                $response = $this->handleSuccessfulCharge($charge, $response);
            }
        } catch (\Stripe\Exception\CardException $e) {
            $this->handleStripeError($e,$response); 
            $response['error'] = "Error: " . $e->getMessage();
            return $response;
        } catch (\Stripe\Exception\RateLimitException $e) {
            $this->handleStripeError($e , $response); 
            $response['error'] = "Error: " . $e->getMessage();
            return $response;
        } catch (\Stripe\Exception\InvalidRequestException $e) {
            $this->handleStripeError($e , $response); 
            $response['error'] = "Error: " . $e->getMessage();
            return $response;
        } catch (\Stripe\Exception\AuthenticationException $e) {
            $this->handleStripeError($e , $response);
            $response['error'] = "Error: " . $e->getMessage();
            return $response;
        } catch (\Stripe\Exception\ApiConnectionException $e) {
            $this->handleStripeError($e , $response); 
            $response['error'] = "Error: " . $e->getMessage();
            return $response;
        } catch (\Stripe\Exception\ApiErrorException $e) {
            $this->handleStripeError($e , $response); 
            $response['error'] = "Error: " . $e->getMessage();
            return $response;
        } catch (Exception $e) {

            Logger::error("Generic Exception: " . $e->getMessage());
            
            Logger::debug("Stack Trace: " . $e->getTraceAsString());
            $response['error'] = "Error: " . $e->getMessage();
            return $response;
        }

        return $response;
    }

    /**
     * Initialize the response structure
     *
     * @return array
     */
    private function initializeresponse()
    {
        return [
            'stripeId' => null,
            'transactionStatus' => null,
            'txnId' => null,
            'error' => null
        ];
    }

    /**
     * Create a Stripe customer from the provided data
     *
     * @param array $stripeData
     * @return \Stripe\Customer
     */
    private function createStripeCustomer($stripeData)
    {
        return \Stripe\Customer::create([
            'email' => $stripeData['email'],
            'name' => $stripeData['name'],
            'phone' => $stripeData['phone'],
            'source' => $stripeData['stripeToken'],
            'address' => $this->generateCustomerAddress(),
        ]);
    }

    /**
     * Generate customer address
     *
     * @return array
     */
    private function generateCustomerAddress()
    {
        return [
            "city" => "Indore",
            "country" => "India",
            "postal_code" => "452001",
            "state" => "MP"
        ];
    }

    /**
     * Process the payment by creating a charge
     *
     * @param string $customerId
     * @param int $amount
     * @param string $currency
     * @return \Stripe\Charge|null
     */
    private function processPayment($customerId, $amount, $currency)
    {
        $paymentData = [
            'customer' => $customerId,
            'amount' => $amount,
            'currency' => $currency,
            'description' => "payment test"
        ];

        return \Stripe\Charge::create($paymentData);
    }

    /**
     * Handle the successful charge and update response
     *
     * @param \Stripe\Charge $charge
     * @param array $response
     * @return array
     */
    private function handleSuccessfulCharge($charge, $response)
    {
        
        $response['stripeId'] = $charge->id;
        $response['txnId'] = $charge->balance_transaction;
        $response['transactionStatus'] = ($charge->status === 'succeeded') ? 'Success' : $charge->status;
        Logger::info(serialize($response));
        return $response;
    }

    /**
     * Handle Stripe specific errors
     *
     * @param \Stripe\Exception\StripeException $e
     * @param array $response
     * @return array
     */
    private function handleStripeError($e, $response)
    {   
        Logger::error("Stripe payment error: " . $e->getMessage());
        $response['error'] = "Error: " . $e->getMessage();
        return $response;
    }

    /**
     * Handle generic errors (non-Stripe related)
     *
     * @param Exception $e
     * @param array $response
     * @return array
     */
    private function handleGenericError($e, $response)
    {
        Logger::error("Generic payment error: " . $e->getMessage());
        $response['error'] = "Error: " . $e->getMessage();
        return $response;
    }

     /**
     * Handle Getting Order Status from reverse Payment
     *
     * @param array $data
     * @return array
     */

    public function getOrderStatus($data)
    {
       
        $response = $this->initializeresponse();
        $gatewayDetails = json_decode($data['gatewayConfig'] , true);       
        $this->stripeClient = new \Stripe\StripeClient($gatewayDetails['secretKey']);
        try{
            $charge = $this->stripeClient->charges->retrieve(
                $data['txnId'],
                []
            );
            $response['stripeId'] = $charge->id;
            $response['txnId'] = $charge->balance_transaction;
            $response['transactionStatus'] = ($charge->status === 'succeeded') ? 'Success' : $charge->status;
           
            return $response;
        }catch (\Stripe\Exception\CardException $e) {
            $this->handleStripeError($e,$response); 
            $response['error'] = "Error: " . $e->getMessage();
            return $response;
        } catch (\Stripe\Exception\RateLimitException $e) {
            $this->handleStripeError($e , $response); 
            $response['error'] = "Error: " . $e->getMessage();
            return $response;
        } catch (\Stripe\Exception\InvalidRequestException $e) {
            $this->handleStripeError($e , $response); 
            $response['error'] = "Error: " . $e->getMessage();
            return $response;
        } catch (\Stripe\Exception\AuthenticationException $e) {
            $this->handleStripeError($e , $response);
            $response['error'] = "Error: " . $e->getMessage();
            return $response;
        } catch (\Stripe\Exception\ApiConnectionException $e) {
            $this->handleStripeError($e , $response); 
            $response['error'] = "Error: " . $e->getMessage();
            return $response;
        } catch (\Stripe\Exception\ApiErrorException $e) {
            $this->handleStripeError($e , $response); 
            $response['error'] = "Error: " . $e->getMessage();
            return $response;
        } catch (Exception $e) {

            Logger::error("Generic Exception: " . $e->getMessage());
            
            Logger::debug("Stack Trace: " . $e->getTraceAsString());
            $response['error'] = "Error: " . $e->getMessage();
            return $response;
        }      

    }
}
?>
