<?php

namespace App\Libraries;

class PhonePeService
{
    private string $baseUrl;
    private string $clientId;
    private string $clientSecret;
    private int $clientVersion;

    public function __construct()
    {
        $this->baseUrl = 'https://api-preprod.phonepe.com/apis/pg-sandbox';
        $this->clientId = (string) setting('phonepe_client_id', '');
        $this->clientSecret = (string) setting('phonepe_client_secret', '');
        $this->clientVersion = (int) setting('phonepe_client_version', 1);
    }

    public function isConfigured(): bool
    {
        return $this->clientId !== '' && $this->clientSecret !== '' && $this->clientVersion > 0;
    }

    public function getAccessToken(): array
    {
        $url = $this->baseUrl . '/v1/oauth/token';
        $payload = http_build_query([
            'client_id' => $this->clientId,
            'client_version' => (string) $this->clientVersion,
            'client_secret' => $this->clientSecret,
            'grant_type' => 'client_credentials',
        ]);
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/x-www-form-urlencoded',
            ],
            CURLOPT_POSTFIELDS => $payload,
            CURLOPT_TIMEOUT => 15,
        ]);
        $body = curl_exec($ch);
        $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $err = curl_error($ch);
        curl_close($ch);

        if ($err) {
            return ['success' => false, 'message' => 'PhonePe token request failed'];
        }
        $json = json_decode((string) $body, true);
        if ($httpCode >= 200 && $httpCode < 300 && is_array($json) && !empty($json['access_token'])) {
            return [
                'success' => true,
                'access_token' => (string) $json['access_token'],
                'token_type' => (string) ($json['token_type'] ?? 'O-Bearer'),
                'raw' => $json,
            ];
        }
        return ['success' => false, 'message' => 'PhonePe token response invalid', 'raw' => $json];
    }

    public function createCheckout(string $merchantOrderId, int $amountPaise, string $redirectUrl): array
    {
        $token = $this->getAccessToken();
        if (empty($token['success'])) {
            return $token;
        }
        $url = $this->baseUrl . '/checkout/v2/pay';
        $req = [
            'merchantOrderId' => $merchantOrderId,
            'amount' => $amountPaise,
            'paymentFlow' => [
                'type' => 'PG_CHECKOUT',
                'merchantUrls' => [
                    'redirectUrl' => $redirectUrl,
                ],
            ],
        ];
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'Authorization: ' . ((string) $token['token_type']) . ' ' . ((string) $token['access_token']),
            ],
            CURLOPT_POSTFIELDS => json_encode($req),
            CURLOPT_TIMEOUT => 20,
        ]);
        $body = curl_exec($ch);
        $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $err = curl_error($ch);
        curl_close($ch);

        if ($err) {
            return ['success' => false, 'message' => 'PhonePe pay request failed'];
        }
        $json = json_decode((string) $body, true);
        if ($httpCode >= 200 && $httpCode < 300 && is_array($json)) {
            $redirect = '';
            if (!empty($json['redirectUrl'])) {
                $redirect = (string) $json['redirectUrl'];
            } elseif (!empty($json['data']['instrumentResponse']['redirectInfo']['url'])) {
                $redirect = (string) $json['data']['instrumentResponse']['redirectInfo']['url'];
            } elseif (!empty($json['data']['redirectUrl'])) {
                $redirect = (string) $json['data']['redirectUrl'];
            }

            $providerOrderId = '';
            if (!empty($json['orderId'])) {
                $providerOrderId = (string) $json['orderId'];
            } elseif (!empty($json['data']['orderId'])) {
                $providerOrderId = (string) $json['data']['orderId'];
            } elseif (!empty($json['data']['payload']['orderId'])) {
                $providerOrderId = (string) $json['data']['payload']['orderId'];
            }

            $merchantId = '';
            if (!empty($json['merchantId'])) {
                $merchantId = (string) $json['merchantId'];
            } elseif (!empty($json['data']['merchantId'])) {
                $merchantId = (string) $json['data']['merchantId'];
            } else {
                $merchantId = $this->clientId;
            }

            $orderToken = '';
            if (!empty($json['token'])) {
                $orderToken = (string) $json['token'];
            } elseif (!empty($json['orderToken'])) {
                $orderToken = (string) $json['orderToken'];
            } elseif (!empty($json['data']['token'])) {
                $orderToken = (string) $json['data']['token'];
            } elseif (!empty($json['data']['orderToken'])) {
                $orderToken = (string) $json['data']['orderToken'];
            } elseif (!empty($json['data']['payload']['token'])) {
                $orderToken = (string) $json['data']['payload']['token'];
            } elseif (!empty($json['data']['instrumentResponse']['redirectInfo']['token'])) {
                $orderToken = (string) $json['data']['instrumentResponse']['redirectInfo']['token'];
            } else {
                $parts = parse_url($redirect);
                if (!empty($parts['query'])) {
                    parse_str((string) $parts['query'], $query);
                    if (!empty($query['token'])) {
                        $orderToken = (string) $query['token'];
                    } elseif (!empty($query['orderToken'])) {
                        $orderToken = (string) $query['orderToken'];
                    } elseif (!empty($query['order_token'])) {
                        $orderToken = (string) $query['order_token'];
                    }
                }
            }

            if ($orderToken !== '') {
                return [
                    'success' => true,
                    'redirect_url' => $redirect,
                    'order_id' => $providerOrderId !== '' ? $providerOrderId : $merchantOrderId,
                    'merchant_order_id' => $merchantOrderId,
                    'order_token' => $orderToken,
                    'merchant_id' => $merchantId,
                    'raw' => $json,
                ];
            }

            return ['success' => false, 'message' => 'PhonePe order token missing', 'raw' => $json];
        }
        return ['success' => false, 'message' => 'PhonePe pay response invalid', 'raw' => $json];
    }

    public function getOrderStatus(string $merchantOrderId): array
    {
        $token = $this->getAccessToken();
        if (empty($token['success'])) {
            return $token;
        }
        $url = $this->baseUrl . '/checkout/v2/order/' . rawurlencode($merchantOrderId) . '/status';
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Accept: application/json',
                'Authorization: ' . ((string) $token['token_type']) . ' ' . ((string) $token['access_token']),
            ],
            CURLOPT_TIMEOUT => 20,
        ]);
        $body = curl_exec($ch);
        $httpCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $err = curl_error($ch);
        curl_close($ch);

        if ($err) {
            return ['success' => false, 'message' => 'PhonePe status request failed'];
        }
        $json = json_decode((string) $body, true);
        if ($httpCode >= 200 && $httpCode < 300 && is_array($json)) {
            return ['success' => true, 'raw' => $json];
        }
        return ['success' => false, 'message' => 'PhonePe status response invalid', 'raw' => $json];
    }
}
