<?php

namespace App\Services;

use App\Enum\TradeMode;
use App\Enum\TradeStatus;
use App\Enum\TradeType;
use App\Models\User;
use App\Models\Trade;
use App\Models\Market;
use App\Models\Transaction;
use App\Enum\TransactionType;
use App\Enum\TransactionMethod;
use App\Enum\TransactionStatus;
use App\Enum\TransactionDirection;
use Illuminate\Support\Facades\DB;

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

    public function openTrade(User $user, Market $market, string $type, string $mode, float $amount): Trade
    {

        $wallet = $mode === TradeMode::LIVE->value ? 'balance' : 'demo_balance';

        if ($user->$wallet < $amount) {
            throw new \Exception("Insufficient {$mode} balance");
        }

        return DB::transaction(function () use ($user, $market, $type, $mode, $amount, $wallet) {

            $trade = Trade::create([
                'user_id'     => $user->id,
                'market_id'   => $market->id,
                'type'        => $type,
                'mode'        => $mode,
                'amount'      => $amount,
                'entry_price' => $market->price,
                'opened_at'   => now(),
            ]);

            // Deduct from correct wallet
            $user->decrement($wallet, $amount);

            // Record the transaction
            $this->openTradeSaveTransaction($user->id, $amount);

            return $trade;
        });
    }

    public function closeTrade(Trade $trade): Trade
    {
        if ($trade->status->value === TradeStatus::CLOSED->value) {
            throw new \Exception('Trade already closed');
        }

        $wallet = $trade->mode->value === TradeMode::LIVE->value ? 'balance' : 'demo_balance';

        return DB::transaction(function () use ($trade, $wallet) {

            $exitPrice = $trade->market->price;

            $profit = $this->calculateProfit(
                $trade->type->value,
                $trade->amount,
                $trade->entry_price,
                $exitPrice
            );

            $trade->update([
                'exit_price' => $exitPrice,
                'profit'     => $profit,
                'status'     => TradeStatus::CLOSED,
                'closed_at'  => now(),
            ]);

            // Credit correct wallet
            $trade->user->increment($wallet, $trade->amount + $profit);

            // Record the profit transaction
            $this->closeTradeSaveTransaction($trade->user->id, $profit);

            return $trade;
        });
    }

    protected function calculateProfit($type, $amount, $entry, $exit): float
    {
        if ($entry <= 0) {
            throw new \LogicException('Invalid entry price for trade profit calculation.');
        }

        if ($amount <= 0) {
            throw new \LogicException('Invalid trade amount.');
        }

        $priceDifference = $exit - $entry;

        if ($type === TradeType::SELL->value) {
            $priceDifference = $entry - $exit;
        }

        return round(($priceDifference / $entry) * $amount, 2);
    }

    protected function closeTradeSaveTransaction($userID, $profit)
    {
        Transaction::create([
            'user_id' => $userID,
            'type' => TransactionType::PROFIT,
            'direction' => TransactionDirection::CREDIT,
            'description' => 'Trade profit',
            'amount' => $profit,
            'method' => TransactionMethod::TRADE,
            'transaction_at' => now(),
            'reference_id' => generateReferenceId(),
            'status' => TransactionStatus::COMPLETED
        ]);
    }

    protected function openTradeSaveTransaction($userID, $amount)
    {
        Transaction::create([
            'user_id' => $userID,
            'type' => TransactionType::WITHDRAW,
            'direction' => TransactionDirection::DEBIT,
            'description' => 'Trade deposit',
            'amount' => $amount,
            'method' => TransactionMethod::TRADE,
            'transaction_at' => now(),
            'reference_id' => generateReferenceId(),
            'status' => TransactionStatus::COMPLETED
        ]);
    }
}
