<?php

namespace App\Services;

use App\Models\User;
use App\Models\Swap;
use App\Models\Market;
use App\Enum\TransactionType;
use App\Enum\TransactionMethod;
use App\Enum\TransactionStatus;
use App\Enum\TransactionDirection;
use Illuminate\Support\Facades\DB;

class SwapService
{
    protected const SWAP_FEE_PERCENTAGE = 0.5; // 0.5% fee

    /**
     * Create a new class instance.
     */
    public function __construct()
    {
        //
    }

    /**
     * Execute a swap transaction
     */
    public function executeSwap(User $user, Market $fromMarket, Market $toMarket, float $fromAmount): Swap
    {
        // Check if user has sufficient balance in the FROM market
        if (!WalletService::hasSufficientBalance($user, $fromMarket, $fromAmount)) {
            $currentBalance = WalletService::getUserMarketBalance($user, $fromMarket)?->balance ?? 0;
            throw new \Exception("Insufficient {$fromMarket->asset} balance. Required: {$fromAmount}, Available: {$currentBalance}");
        }

        return DB::transaction(function () use ($user, $fromMarket, $toMarket, $fromAmount) {
            // Calculate amount received using REAL market prices from CoinGecko
            $toAmount = PriceService::calculateSwapAmount($fromMarket, $toMarket, $fromAmount);

            // Calculate exchange rate
            $rate = $toAmount > 0 ? round($toAmount / $fromAmount, 8) : 0;

            // Calculate fee
            $fee = $this->calculateFee($fromAmount);

            // Create swap record
            $swap = Swap::create([
                'user_id' => $user->id,
                'from_market_id' => $fromMarket->id,
                'to_market_id' => $toMarket->id,
                'from_amount' => $fromAmount,
                'to_amount' => $toAmount,
                'rate' => $rate,
                'fee' => $fee,
                'status' => 'completed',
                'swapped_at' => now(),
            ]);

            // Deduct from the FROM market balance (including fee)
            WalletService::deductBalance($user, $fromMarket, $fromAmount + $fee);

            // Add to the TO market balance
            WalletService::addBalance($user, $toMarket, $toAmount);

            // Record transaction - Debit (swap out)
            $this->recordTransaction(
                $user->id,
                TransactionType::WITHDRAW,
                TransactionDirection::DEBIT,
                $fromAmount,
                "Swap {$fromMarket->asset} to {$toMarket->asset}",
                $swap->uuid
            );

            // Record transaction - Credit (swap in)
            $this->recordTransaction(
                $user->id,
                TransactionType::DEPOSIT,
                TransactionDirection::CREDIT,
                $toAmount,
                "Received from swap {$fromMarket->asset} to {$toMarket->asset}",
                $swap->uuid
            );

            // Record fee transaction
            if ($fee > 0) {
                $this->recordTransaction(
                    $user->id,
                    TransactionType::WITHDRAW,
                    TransactionDirection::DEBIT,
                    $fee,
                    "Swap fee",
                    $swap->uuid
                );
            }

            return $swap;
        });
    }

    /**
     * Calculate exchange rate between two markets
     */
    protected function calculateExchangeRate(Market $fromMarket, Market $toMarket): float
    {
        $fromPrice = $fromMarket->price > 0 ? $fromMarket->price : 1;
        $toPrice = $toMarket->price > 0 ? $toMarket->price : 1;

        return round($fromPrice / $toPrice, 8);
    }

    /**
     * Calculate amount to receive after swap
     */
    protected function calculateSwapAmount(float $fromAmount, float $rate): float
    {
        return round($fromAmount * $rate, 8);
    }

    /**
     * Calculate swap fee
     */
    protected function calculateFee(float $amount): float
    {
        return round(($amount * self::SWAP_FEE_PERCENTAGE) / 100, 8);
    }

    /**
     * Record transaction in transaction history
     */
    protected function recordTransaction(
        int $userId,
        TransactionType $type,
        TransactionDirection $direction,
        float $amount,
        string $description,
        string $referenceId
    ): void {
        // Check if Transaction model exists, if so record it
        if (class_exists(\App\Models\Transaction::class)) {
            \App\Models\Transaction::create([
                'user_id' => $userId,
                'type' => $type,
                'direction' => $direction,
                'description' => $description,
                'amount' => $amount,
                'method' => TransactionMethod::SWAP,
                'transaction_at' => now(),
                'reference_id' => $referenceId,
                'status' => TransactionStatus::COMPLETED
            ]);
        }
    }
}
