<?php

namespace App;

use GuzzleHttp\Client;
use Stripe\StripeClient;
use Stripe\Exception\ApiErrorException;

class PaymentIntentService
{
    private $ucrmApiUrl;
    private $ucrmApiKey;
    private $stripeApiKey;
    private $httpClient;
    private $stripeClient;
    private $logger;

    public function __construct($ucrmApiUrl, $ucrmApiKey, $stripeApiKey, $logger = null)
    {
        $this->ucrmApiUrl = rtrim($ucrmApiUrl, '/');
        $this->ucrmApiKey = $ucrmApiKey;
        $this->stripeApiKey = $stripeApiKey;
        $this->logger = $logger;

        $this->httpClient = new Client([
            'base_uri' => $this->ucrmApiUrl . '/api/v1.0/',
            'headers' => [
                'X-Auth-App-Key' => $this->ucrmApiKey,
                'Accept' => 'application/json',
            ],
            'verify' => false,
            'timeout' => 10,
        ]);

        $this->stripeClient = new StripeClient($this->stripeApiKey);
    }

    public function searchClients($query)
    {
        try {
            $response = $this->httpClient->get('clients', [
                'query' => [
                    'query' => $query,
                    'limit' => 5
                ]
            ]);

            $clients = json_decode($response->getBody(), true);
            
            return array_map(function ($client) {
                return [
                    'id' => $client['id'],
                    'firstName' => $client['firstName'],
                    'lastName' => $client['lastName'],
                    'username' => $client['username'],
                    'fullAddress' => $client['fullAddress'] ?? '',
                    'companyName' => $client['companyName'],
                    'clientType' => $client['clientType'], // 1 = residential, 2 = company
                ];
            }, $clients);

        } catch (\Exception $e) {
            return ['error' => $e->getMessage()];
        }
    }

    public function getClientDetails($clientId)
    {
        try {
            $response = $this->httpClient->get("clients/{$clientId}");
            $client = json_decode($response->getBody(), true);

            $stripeCustomerId = null;
            $clabeInterbancaria = null;
            if (isset($client['attributes'])) {
                foreach ($client['attributes'] as $attribute) {
                    if ($attribute['key'] === 'stripeCustomerId' || $attribute['name'] === 'Stripe Customer ID') {
                        $stripeCustomerId = $attribute['value'];
                    }
                    if ($attribute['key'] === 'clabeInterbancaria' || $attribute['name'] === 'Clabe Interbancaria') {
                        $clabeInterbancaria = $attribute['value'];
                    }
                }
            }

            return [
                'id' => $client['id'],
                'fullName' => ($client['clientType'] == 1) 
                    ? $client['firstName'] . ' ' . $client['lastName'] 
                    : $client['companyName'],
                'stripeCustomerId' => $stripeCustomerId,
                'clabeInterbancaria' => $clabeInterbancaria,
                'email' => $this->getClientEmail($client),
                'accountOutstanding' => $client['accountOutstanding'] ?? 0
            ];

        } catch (\Exception $e) {
            return ['error' => $e->getMessage()];
        }
    }

    private function getClientEmail($clientData)
    {
        if (!empty($clientData['contacts'])) {
            foreach ($clientData['contacts'] as $contact) {
                if (!empty($contact['email'])) {
                    return $contact['email'];
                }
            }
        }
        return $clientData['username'] ?? ''; // Fallback, though username might not be email
    }

    public function createPaymentIntent($clientId, $amount, $stripeCustomerId, $adminId = null)
    {
        if ($amount < 10) {
            throw new \Exception("El monto debe ser mayor a 10 MXN");
        }

        try {
            $amountCentavos = intval($amount * 100);

            // DEBUG: Check Customer Balance
            try {
                $balanceObj = $this->stripeClient->customers->retrieveCashBalance(
                    $stripeCustomerId,
                    []
                );
                $availableBalance = $balanceObj->available['mxn'] ?? 0;
                error_log("DEBUG PLUGIN: Customer $stripeCustomerId Balance: " . json_encode($balanceObj));
            } catch (\Exception $e) {
                error_log("DEBUG PLUGIN: Could not fetch balance: " . $e->getMessage());
            }

            $paymentIntent = $this->stripeClient->paymentIntents->create([
                'amount' => $amountCentavos,
                'currency' => 'mxn',
                'customer' => $stripeCustomerId,
                'payment_method_types' => ['customer_balance'],
                'payment_method_data' => ['type' => 'customer_balance'],
                'confirm' => true,
                'payment_method_options' => [
                    'customer_balance' => [
                        'funding_type' => 'bank_transfer',
                        'bank_transfer' => ['type' => 'mx_bank_transfer']
                    ],
                ],
                'metadata' => [
                    'clientId' => $clientId,
                    'createdBy' => 'UCRM Plugin',
                    'paymentType' => 'card.one_time',
                    'signedInAdminId' => $adminId, // Will be passed from session or fixed
                    'tipoPago' => 'Transferencia Bancaria Manual'
                ],
            ]);

            return [
                'success' => true,
                'id' => $paymentIntent->id,
                'status' => $paymentIntent->status,
                'amount' => $paymentIntent->amount / 100,
                'currency' => $paymentIntent->currency,
                'next_action' => $paymentIntent->next_action
            ];

        } catch (ApiErrorException $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        } catch (\Exception $e) {
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }

    public function getPaymentIntent($pk)
    {
        try {
            return $this->stripeClient->paymentIntents->retrieve($pk);
        } catch (\Exception $e) {
            return null;
        }
    }

    public function registerPayment($clientId, $amount, $currency, $notes = '')
    {
        try {
            $methodId = $this->getPaymentMethodIdByName('Transferencia bancaria');
            if (!$methodId) {
                $this->log("Payment Registration Error: Could not find payment method 'Transferencia bancaria'");
                return false;
            }

            $response = $this->httpClient->post('payments', [
                'json' => [
                    'clientId' => (int)$clientId,
                    'amount' => $amount,
                    'currencyCode' => strtoupper($currency),
                    'methodId' => $methodId,
                    'note' => $notes,
                    'createdDate' => date('c'),
                ]
            ]);
            
            $this->log("UCRM Payment Registration Response: " . $response->getStatusCode() . " - " . $response->getBody());
            
            return true;
        } catch (\Exception $e) {
            $this->log("Payment Registration Error: " . $e->getMessage());
            return false;
        }
    }

    private function log($message)
    {
        if ($this->logger) {
            $this->logger->appendLog($message);
        } else {
            error_log($message);
        }
    }

    private function getPaymentMethodIdByName($name)
    {
        try {
            $response = $this->httpClient->get('payment-methods');
            $methods = json_decode($response->getBody(), true);
            foreach ($methods as $method) {
                if ($method['name'] === $name) {
                    return $method['id'];
                }
            }
        } catch (\Exception $e) {
            error_log("Error fetching payment methods: " . $e->getMessage());
        }
        return null;
    }
}

