<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Cache;

class MpesaService
{
    protected $consumerKey;
    protected $consumerSecret;
    protected $passkey;
    protected $shortcode;
    protected $environment;
    protected $baseUrl;

    public function __construct()
    {
        // Load from environment with validation
        $this->consumerKey = env('MPESA_CONSUMER_KEY');
        $this->consumerSecret = env('MPESA_CONSUMER_SECRET');
        $this->passkey = env('MPESA_PASSKEY');
        $this->shortcode = env('MPESA_SHORTCODE', '174379');
        $this->environment = env('MPESA_ENVIRONMENT', 'sandbox');
        
        // Validate required credentials
        $this->validateCredentials();
        
        $this->baseUrl = $this->environment === 'production' 
            ? 'https://api.safaricom.co.ke'
            : 'https://sandbox.safaricom.co.ke';
    }

    /**
     * Validate that required credentials are set
     */
    private function validateCredentials()
    {
        $missing = [];
        
        if (empty($this->consumerKey)) {
            $missing[] = 'MPESA_CONSUMER_KEY';
        }
        if (empty($this->consumerSecret)) {
            $missing[] = 'MPESA_CONSUMER_SECRET';
        }
        if (empty($this->passkey)) {
            $missing[] = 'MPESA_PASSKEY';
        }
        
        if (!empty($missing)) {
            $message = 'Missing M-Pesa credentials: ' . implode(', ', $missing) . 
                       '. Please check your .env file and run php artisan config:clear';
            Log::error($message);
            throw new \Exception($message);
        }
    }

    /**
     * Get OAuth Access Token
     */
    public function getAccessToken()
    {
        $cacheKey = 'mpesa_access_token';
        
        // Check cache first
        if (Cache::has($cacheKey)) {
            return Cache::get($cacheKey);
        }

        $url = $this->baseUrl . '/oauth/v1/generate?grant_type=client_credentials';
        
        try {
            $response = Http::withBasicAuth($this->consumerKey, $this->consumerSecret)
                ->timeout(30)
                ->get($url);

            if ($response->successful()) {
                $token = $response->json()['access_token'];
                // Cache for 55 minutes (token expires in 1 hour)
                Cache::put($cacheKey, $token, 3300);
                Log::info('M-Pesa access token obtained successfully');
                return $token;
            } else {
                Log::error('Failed to get M-Pesa access token', [
                    'status' => $response->status(),
                    'response' => $response->body()
                ]);
                throw new \Exception('Failed to authenticate with M-Pesa: ' . $response->body());
            }
        } catch (\Exception $e) {
            Log::error('M-Pesa authentication error: ' . $e->getMessage());
            throw new \Exception('Could not connect to M-Pesa: ' . $e->getMessage());
        }
    }

    /**
     * Initiate STK Push (Lipa Na M-Pesa Online)
     */
    public function stkPush($phoneNumber, $amount, $accountReference, $transactionDesc)
    {
        $accessToken = $this->getAccessToken();
        $timestamp = $this->getTimestamp();
        $password = $this->generatePassword($timestamp);
        
        $url = $this->baseUrl . '/mpesa/stkpush/v1/processrequest';
        
        // IMPORTANT: Use proper callback URL
        $callbackUrl = env('MPESA_CALLBACK_URL');
        
        // Validate callback URL
        // if (empty($callbackUrl) || $callbackUrl == 'https://unsmoldering-polyphonic-milo.ngrok-free.dev/mpesa/callback') {
        //     // Fallback to ngrok or public URL
        //     $callbackUrl = url('/mpesa/callback');
        //     Log::warning('Using fallback callback URL: ' . $callbackUrl);
        // }
        
        // Ensure callback URL uses HTTPS (Safaricom requires HTTPS in production)
        // if (env('MPESA_ENVIRONMENT') === 'production' && strpos($callbackUrl, 'https://') !== 0) {
        //     throw new \Exception('Production environment requires HTTPS callback URL');
        // }
        $callbackUrl = 'https://unsmoldering-polyphonic-milo.ngrok-free.dev/mpesa/callback';
        
        $payload = [
            'BusinessShortCode' => $this->shortcode,
            'Password' => $password,
            'Timestamp' => $timestamp,
            'TransactionType' => 'CustomerPayBillOnline',
            'Amount' => (int) $amount,
            'PartyA' => $phoneNumber,
            'PartyB' => $this->shortcode,
            'PhoneNumber' => $phoneNumber,
            'CallBackURL' => $callbackUrl,
            'AccountReference' => $accountReference,
            'TransactionDesc' => substr($transactionDesc, 0, 36)
        ];

        Log::info('STK Push Request', [
            'payload' => $payload,
            'url' => $url
        ]);

        try {
            $response = Http::withToken($accessToken)
                ->timeout(30)
                ->post($url, $payload);

            Log::info('STK Push Response', [
                'status' => $response->status(),
                'body' => $response->json()
            ]);

            if ($response->successful()) {
                return (object) $response->json();
            } else {
                throw new \Exception('STK Push failed: ' . $response->body());
            }
        } catch (\Exception $e) {
            Log::error('STK Push Exception: ' . $e->getMessage());
            throw $e;
        }
    }

    /**
     * Generate password for STK Push
     */
    protected function generatePassword($timestamp)
    {
        $str = $this->shortcode . $this->passkey . $timestamp;
        return base64_encode($str);
    }

    /**
     * Get current timestamp in required format
     */
    protected function getTimestamp()
    {
        return date('YmdHis');
    }

    /**
     * Query transaction status
     */
    public function queryStatus($checkoutRequestId)
    {
        $accessToken = $this->getAccessToken();
        $timestamp = $this->getTimestamp();
        $password = $this->generatePassword($timestamp);
        
        $url = $this->baseUrl . '/mpesa/stkpushquery/v1/query';
        
        $payload = [
            'BusinessShortCode' => $this->shortcode,
            'Password' => $password,
            'Timestamp' => $timestamp,
            'CheckoutRequestID' => $checkoutRequestId
        ];

        try {
            $response = Http::withToken($accessToken)
                ->timeout(30)
                ->post($url, $payload);

            if ($response->successful()) {
                return (object) $response->json();
            }
            throw new \Exception('Query failed: ' . $response->body());
        } catch (\Exception $e) {
            Log::error('Query Status Exception: ' . $e->getMessage());
            throw $e;
        }
    }
}