<?php 

namespace Modules\transactionwallet\Services;

use Carbon\Carbon;
use Exception;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Modules\auth\Models\Customer;
use Modules\auth\Models\CustomerWallet;
use Modules\transactionwallet\Enums\TransactionType;
use Modules\transactionwallet\Models\CryptoTransaction;
use Modules\transactionwallet\Models\CryptoWallet;
use Throwable;

class CryptoTransactionService
{    

    public function getTransaction(array $filter = [])
    {
        // 1. Build the base query
        $query = CryptoTransaction::query();
        if (!empty($filter) && isset($filter['customer_id'])) {
            $query->where('customer_id', $filter['customer_id']);            
        }
        if (!empty($filter) && isset($filter['type'])) {
            $query->where('type', $filter['type']);
        }
        
        /*        
            // 3. Récupérer tous les réseaux utilisés (par exemple bitcoin, ethereum...)
            $networks = $transactions->pluck('network')
                ->filter() // on enlève les valeurs nulles
                ->map(fn($n) => strtolower($n))
                ->unique()
                ->implode(',');

            // 4. Appel API CoinGecko
            $response = Http::get('https://api.coingecko.com/api/v3/coins/markets', [
                'vs_currency' => 'usd',
                'ids' => $networks,
            ]);

            $apiData = collect($response->json())->keyBy('id'); // indexé par 'bitcoin', 'ethereum', etc.

            // 5. Injecter les données dans chaque transaction
            $transactions->getCollection()->transform(function ($tx) use ($apiData) {
                $networkId = strtolower($tx->network);
                $crypto = $apiData->get($networkId);

                if ($crypto) {
                    $tx->crypto_name = $crypto['name'];
                    $tx->crypto_symbol = strtoupper($crypto['symbol']);
                    $tx->crypto_image = $crypto['image'];
                    $tx->crypto_price = $crypto['current_price'];
                } else {
                    // Valeurs par défaut si pas trouvé dans l'API
                    $tx->crypto_name = ucfirst($tx->network);
                    $tx->crypto_symbol = strtoupper($tx->network);
                    $tx->crypto_image = null;
                    $tx->crypto_price = null;
                }

                return $tx;
            });
        */
        
        $transactions = $query->orderByDesc('created_at')->paginate(50);

        return $transactions;
    }    

    public function wallets(string $currency = 'usd')
    {
        return Cache::remember("coingecko.wallets:{$currency}", 300, function () use ($currency) {            
            $targetSymbols = ['btc', 'eth', 'usdt', 'bnb', 'sol', 'xrp', 'ada', 'doge', 'ltc', 'xmr', 'matic', 'trx'];
            $response = Http::get('https://api.coingecko.com/api/v3/coins/markets', [
                'vs_currency' => $currency,
                'order' => 'market_cap_desc',
                'per_page' => 100,
                'page' => 1,
                'sparkline' => false,
                'price_change_percentage' => '24h',
            ]);

            if ($response->failed()) {
                return collect(); // ou éventuellement throw ou fallback
            }

            $coins = collect($response->json())
                ->filter(function ($coin) use ($targetSymbols) {
                    return in_array(strtolower($coin['symbol']), $targetSymbols);
                });

            $coins->push([
                'id' => 'eur',
                'symbol' => 'eur',
                'name' => 'Euro',
                'image' => 'https://img.icons8.com/?size=100&id=7992&format=png&color=000000', // ou une image personnalisée
                'current_price' => 1,
                'market_cap' => null,
                'price_change_percentage_24h' => 0,
            ]);            

            return $coins->sortBy(function ($coin) use ($targetSymbols) {
                    return array_search(strtolower($coin['symbol']), $targetSymbols);
                })
                ->values(); // pour réindexer de 0 à N
        });
    }

    /**
     * Store a deposit transaction (external or internal)
     *
     * @param CryptoWallet $walletTarget
     * @param float $amount
     * @param string|null $fromAddress
     * @param float $fee
     * @param string $network
     * @return CryptoTransaction
     * @throws Exception
     */
    public function store(string $type, array $customer, array $transaction, array $wallet, string $iban, string $rib, float $amount = 0, float $amount_send_usd = 0)
    {        
        #dd($type, $customer, $transaction, $wallet, $iban, $rib, $amount = 0);
        if ($amount < 0) throw new Exception("Le montant doit être supérieur à zéro.");
        
        return DB::transaction(function () use ($type, $customer, $transaction, $wallet, $iban, $rib, $amount, $amount_send_usd) {

            $transaction = CryptoTransaction::create([
                'transaction_id' => $transaction['id'] ?? null,
                'transaction_address' => $transaction['address'],
                'transaction_hash' => $transaction['hash'],
                
                'amount' => round($amount, 8),
                'amount_send_usd' => round($amount_send_usd, 8),

                'customer_id' => $customer['id'],
                'customer_email' => $customer['email'],
                'customer_lastname' => $customer['kyc']['last_name'],
                'customer_firstname' => $customer['kyc']['first_name'],

                'iban' => $iban,
                'rib' => $rib,

                'wallet_id' => $wallet['id'],
                'wallet_symbol' => $wallet['symbol'],
                'wallet_name' => $wallet['name'],
                'wallet_image' => $wallet['image'],
                
                'type' => TransactionType::tryFrom($type)->value,
                
                'status' => 'pending',

                'created_at' => Carbon::now(),
                'updated_at' => Carbon::now(),
            ]);

            // Mise à jour du solde du wallet
            /*$to->balance += ($amount - $fee);
            $to->save();*/

            return $transaction;
        });
    }

    /**
     * Récupère ou crée un wallet pour un utilisateur et une crypto donnée
     */
    protected function getOrCreateWallet(string $email, string $currency)
    {
        // Récupère le CustomerWallet via l'email
        $customerWallet = CustomerWallet::firstOrCreate([
            'mobile_number' => $email, // ou autre identifiant unique
        ]);

        // Récupère ou crée le CryptoWallet
        return CryptoWallet::firstOrCreate([
            'customer_id' => $customerWallet->id,
            'network' => $currency,
        ], [
            'address' => null, // si tu n’as pas l’adresse
            'type' => 'external',
        ]);
    }

    public function update_status(string $transaction_id, string $status, string $rib, string $note): string {
        $s = "";
        if($status == 'confirme'){
            $s = 'confirmed';
        }else if($status == 'reject'){
            $s = 'rejected';
        }elseif($status == 'accept'){
            $s = 'accepted';
        }

        $data['status'] = $s;
        $data['notes'] = is_null($note) ? "N/A" : $note;
        $data['rib'] = $rib;

        if($status == 'approve'){
            $data['confirmed_at'] = Carbon::now();
        }
        CryptoTransaction::where('transaction_id', $transaction_id)->update($data); 

        return $s;
    }

    public function cryptoUSDConvert($amount, $crypto = 'bitcoin', $currency = 'usd')
    {
        try {
            $amountUsd = $amount;
            // On met en cache le prix USD de chaque crypto pendant 10 minutes
            // $cacheKey = "crypto_usd_price_{$crypto}";
            // $cryptoPrice = Cache::remember($cacheKey, now()->addMinutes(10), function () use ($crypto, $currency) {
            //     $response = Http::get('https://api.coingecko.com/api/v3/simple/price', [
            //         'ids' => $crypto,
            //         'vs_currencies' => $currency,
            //     ]);

            //     if ($response->failed()) {
            //         // On log pour le suivi
            //         Log::warning("CoinGecko API request failed for {$crypto}");
            //         return null;
            //     }

            //     $data = $response->json();

            //     return $data[$crypto][$currency] ?? null;
            // });


            $cryptoPrice = null;
            $response = Http::get('https://api.coingecko.com/api/v3/simple/price', [
                'ids' => $crypto,
                'vs_currencies' => $currency,
            ]);

            if ($response->failed()) {
                Log::warning("CoinGecko API request failed for {$crypto}");
            } else {
                $data = $response->json();
                $cryptoPrice = $data[$crypto][$currency] ?? null;
            }


            // Si on n’a pas de prix, on retourne 0
            if (empty($cryptoPrice) || $cryptoPrice <= 0) {
                return 0;
            }

            // Convertir le montant USD en crypto
            return $amountUsd / $cryptoPrice;
        } catch (Throwable $th) {
            throw $th;
        }
    }

    /**
     * Convert a cryptocurrency to a fiat currency
     *
     * @param string $coinSymbol BTC, ETH, etc.
     * @param string $fiatCurrency EUR, USD, etc.
     * @param float $amount Amount of crypto to convert
     * @return float|null
     */
    public function convert(string $coinSymbol, string $fiatCurrency, float $amount = 1): ?float
    {        
        $fiatCurrency = strtolower($fiatCurrency);        
        // Appel à l'API CoinGecko
        $response = Http::get("https://api.coingecko.com/api/v3/simple/price", [
            'ids' => $coinSymbol,
            'vs_currencies' => $fiatCurrency,
        ]);

        if ($response->successful() && isset($response[$coinSymbol][$fiatCurrency])) {
            $rate = $response[$coinSymbol][$fiatCurrency];            
            return $rate * $amount;
        }

        return null; // si échec
    }
}