<?php namespace App\Libraries;

use Exception;
use Razorpay\Api\Api;
use Razorpay\Api\Errors\BadRequestError;
use Razorpay\Api\Errors\SignatureVerificationError;

require_once(APPPATH . 'ThirdParty/Razorpay/Razorpay.php');

class RazorpayClient
{
    private string $returnUrl;
    private string $cancelUrl;
    private Api $razorpay;
    private string $webhookSecretKey;

    /**
     * Create models, config and library's
     */
    function __construct()
    {
        $depositMethods = new DepositMethods();
        $apiKeys = $depositMethods->get_deposit_method_apikeys("razorpay");

        $this->razorpay = new Api($apiKeys["api_value_1"], $apiKeys["api_value_2"]);
        $this->webhookSecretKey = $apiKeys["api_value_3"] ?? '';

        $settings = new Settings();
        $frontUrl = rtrim($settings->get_config("site_url"), '/');
        $this->returnUrl = "$frontUrl/private/profile/subscribe";
        $this->cancelUrl = "$frontUrl/private/profile/subscribe";
    }

    /**************************************************************************************
     * PUBLIC FUNCTIONS
     **************************************************************************************/

    /**
     * Create a payment order
     * @param array $data Data for the order
     * @return array Response with order details or error
     */
    public function create_order(array $data): array
    {
        try {
            // Check if this is a subscription or one-time payment
            if ($data["type"] === "subscription") {
                return $this->create_subscription_order($data);
            }
            
            return $this->create_onetime_order($data);
        } catch (BadRequestError $e) {
            return [
                'event' => false,
                'message' => 'Failed to create order',
                'error' => $e->getMessage(),
            ];
        } catch (Exception $e) {
            return [
                'event' => false,
                'message' => 'Failed to create order',
                'error' => $e->getMessage(),
            ];
        }
    }

    /**
     * Cancel a subscription
     * @param string $subscriptionId The Razorpay subscription ID to cancel
     * @return bool True if successful, throws exception otherwise
     * @throws BadRequestError If the API request fails
     */
    public function cancel_subscription(string $subscriptionId): bool
    {
        $this->razorpay->subscription->fetch($subscriptionId)->cancel();
        return true;
    }

    /**
     * Process webhook event
     * @param string $requestBody Raw request body
     * @param string $signature Razorpay signature from header
     * @return array Processed webhook event data or error
     */
    public function process_webhook(string $requestBody, string $signature): array
    {

        try {
            $this->razorpay->utility->verifyWebhookSignature($requestBody, $signature, $this->webhookSecretKey);
        } catch (SignatureVerificationError $e) {
            return [
                'event' => false,
                'message' => 'Invalid webhook signature',
                'error' => $e->getMessage(),
            ];
        }

        try {
            // Parse the webhook payload
            $payload = json_decode($requestBody, true);
            $event_type = $payload['event'];
            $event_data = $payload['payload'];
            
            // Process different event types
            switch ($event_type) {
                case 'subscription.charged':
                    $entity = $event_data['subscription']['entity'];
                    $notes = $entity['notes'];
                    $custom_id = $notes['app_id'] . "_" . $notes['customer_id'] . "_" . $notes['plan_id'];

                    $payment = $event_data['payment']['entity'];

                    return [
                        'event' => true,
                        'event_type' => $event_type,
                        'resource_id' => $payment['id'],
                        'order_id' => $entity['id'],
                        'paid_count' => $entity['paid_count'],
                        'amount' => $payment['amount'] / 100,
                        'currency' => $payment['currency'],
                        'custom_id' => $custom_id,
                        'customer_id' => $entity['customer_id'] ?? $payment['customer_id'] ?? $notes['customer_id'],
                        'event_data' => $event_data,
                    ];
                case 'subscription.cancelled':
                    $entity = $event_data['subscription']['entity'];
                    $notes = $entity['notes'];
                    $custom_id = $notes['app_id'] . "_" . $notes['customer_id'] . "_" . $notes['plan_id'];

                    return [
                        'event' => true,
                        'event_type' => $event_type,
                        'resource_id' => $entity['id'],
                        'order_id' => $entity['id'],
                        'custom_id' => $custom_id,
                        'customer_id' => $entity['customer_id'] ?? $notes['customer_id'],
                        'event_data' => $event_data,
                    ];
                case 'payment_link.paid':
                    $entity = $event_data['payment']['entity'];
                    $notes = $entity['notes'];
                    $custom_id = $notes['app_id'] . "_" . $notes['customer_id'] . "_" . $notes['plan_id'];

                    $link_id = $event_data['payment_link']['entity']['id'];

                    return [
                        'event' => true,
                        'event_type' => $event_type,
                        'resource_id' => $entity['id'],
                        'order_id' => $link_id,
                        'custom_id' => $custom_id,
                        'amount' => $entity['amount'] / 100,
                        'currency' => $entity['currency'],
                        'customer_id' => $entity['customer_id'] ?? $notes['customer_id'],
                        'event_data' => $event_data,
                    ];

                default:
                    // Other event types
                    return [
                        'event' => false,
                    ];
            }
        } catch (Exception $e) {
            return [
                'event' => false,
                'message' => 'Invalid payload',
                'error' => $e->getMessage(),
            ];
        }
    }

    /**************************************************************************************
     * PRIVATE FUNCTIONS
     **************************************************************************************/

    /**
     * Create a subscription order
     * @param array $data Data for the subscription
     * @return array Response with subscription details or error
     */
    private function create_subscription_order(array $data): array
    {
        $subscription = $this->razorpay->subscription->create([
            "plan_id"         => $data["plan_api_id"],
            "total_count"     => 12,
            "quantity"        => 1,
            "customer_notify" => 1,
            "notes"           => [
                "customer_id" => $data["user_id"],
                "plan_id"     => $data["plan_id"],
                "app_id"      => $data["app_id"]
            ],
        ]);

        return [
            'event' => true,
            'order_id' => $subscription->id,
            'status' => $subscription->status,
            'approval_url' => $subscription->short_url,
            'data' => $subscription,
        ];
    }
    
    /**
     * Create a one-time payment order using Payment Links API
     * @param array $data Data for the one-time payment
     * @return array Response with order details or error
     */
    private function create_onetime_order(array $data): array
    {
        // Convert price to paise (Razorpay uses smallest currency unit)
        $amount = $data["price"] * 100;
        
        // Set expiry time (20 minutes from now)
        $expiresAt = time() + (20 * 60);
        
        // Create payment link options
        $paymentLinkOptions = [
            "amount"          => $amount,
            "currency"        => $data["currency_code"],
            "accept_partial"  => false,
            "notify"          => [
                "sms"   => false,
                "email" => false
            ],
            "reminder_enable" => false,
            "notes"           => [
                "customer_id" => $data["user_id"],
                "plan_id"     => $data["plan_id"],
                "app_id"      => $data["app_id"]
            ],
            "callback_url"    => $this->returnUrl,
            "callback_method" => "get",
            "expire_by"       => $expiresAt,
        ];
        
        // Create the payment link
        $paymentLink = $this->razorpay->paymentLink->create($paymentLinkOptions);
        
        return [
            'event' => true,
            'order_id' => $paymentLink->id,
            'status' => $paymentLink->status,
            'approval_url' => $paymentLink->short_url,
            'data' => $paymentLink,
        ];
    }
}
