<?php

namespace App\Services;

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

class MpesaService
{
    protected $env;
    protected $shortcode;
    protected $consumerKey;
    protected $consumerSecret;
    protected $passkey;
    protected $callbackUrl;

    public function __construct()
    {
        $this->env = config('services.mpesa.env', 'sandbox');
        $this->shortcode = config('services.mpesa.shortcode', '174379'); // Default Daraja sandbox shortcode
        $this->consumerKey = config('services.mpesa.consumer_key');
        $this->consumerSecret = config('services.mpesa.consumer_secret');
        $this->passkey = config('services.mpesa.passkey', 'bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2cbe9'); // Sandbox passkey
        $this->callbackUrl = config('services.mpesa.callback_url', url('/api/v1/payments/mpesa/callback'));
    }

    /**
     * Generate Daraja Access Token
     */
    public function getAccessToken()
    {
        if (empty($this->consumerKey) || empty($this->consumerSecret)) {
            return null;
        }

        $url = $this->env === 'production'
            ? 'https://api.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials'
            : 'https://sandbox.safaricom.co.ke/oauth/v1/generate?grant_type=client_credentials';

        try {
            $response = Http::withBasicAuth($this->consumerKey, $this->consumerSecret)->get($url);
            if ($response->successful()) {
                return $response->json()['access_token'];
            }
        } catch (\Exception $e) {
            Log::error('Mpesa Access Token generation failed: ' . $e->getMessage());
        }

        return null;
    }

    /**
     * Initiate STK Push
     */
    public function initiateStkPush($phone, $amount, $reference)
    {
        // Format Phone number (e.g. 0712345678 or +254712345678 to 254712345678)
        $phone = preg_replace('/[^0-9]/', '', $phone);
        if (str_starts_with($phone, '0')) {
            $phone = '254' . substr($phone, 1);
        } elseif (str_starts_with($phone, '+')) {
            $phone = substr($phone, 1);
        }

        $accessToken = $this->getAccessToken();

        // If no credentials or token is generated, fall back to simulation mode
        if (!$accessToken) {
            Log::info("M-Pesa STK Push Simulation initiated for {$phone}, Amount: {$amount}, Ref: {$reference}");
            return [
                'success' => true,
                'simulation' => true,
                'MerchantRequestID' => 'Sim-' . uniqid(),
                'CheckoutRequestID' => 'Sim-Chk-' . uniqid(),
                'ResponseDescription' => 'Simulation Success. API credentials missing.'
            ];
        }

        $timestamp = date('YmdHis');
        $password = base64_encode($this->shortcode . $this->passkey . $timestamp);
        
        $url = $this->env === 'production'
            ? 'https://api.safaricom.co.ke/mpesa/stkpush/v1/query'
            : 'https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/query'; // STK push URL is same structure

        $url = $this->env === 'production'
            ? 'https://api.safaricom.co.ke/mpesa/stkpush/v1/processrequest'
            : 'https://sandbox.safaricom.co.ke/mpesa/stkpush/v1/processrequest';

        try {
            $response = Http::withToken($accessToken)->post($url, [
                'BusinessShortCode' => $this->shortcode,
                'Password' => $password,
                'Timestamp' => $timestamp,
                'TransactionType' => 'CustomerPayBillOnline',
                'Amount' => round($amount),
                'PartyA' => $phone,
                'PartyB' => $this->shortcode,
                'PhoneNumber' => $phone,
                'CallBackURL' => $this->callbackUrl,
                'AccountReference' => $reference,
                'TransactionDesc' => 'Payment for order ' . $reference
            ]);

            if ($response->successful()) {
                return array_merge(['success' => true], $response->json());
            }

            Log::error('Mpesa STK Push API returned error: ' . $response->body());
            return ['success' => false, 'error' => $response->json()];

        } catch (\Exception $e) {
            Log::error('Mpesa STK Push request failed: ' . $e->getMessage());
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
}
