<?php

namespace App\Http\Controllers;

use App\Models\Account;
use App\Models\Agent;
use App\Models\Currency;
use App\Models\Transaction;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class SellCurrencyController extends Controller
{
    public function create()
    {
        return view('transactions.sell', [
            'agents' => Agent::orderBy('name')->get(),
            'currencies' => Currency::orderBy('code')->get(),
            'accounts' => Account::with('currency')->orderBy('name')->get(),
        ]);
    }

    public function store(Request $request)
    {
        $data = $request->validate([
            'agent_id' => ['nullable', 'exists:agents,id'],
            'currency_id' => ['required', 'exists:currencies,id'],
            'source_account_id' => ['required', 'exists:accounts,id'],
            'target_account_id' => ['required', 'exists:accounts,id'],
            'quantity' => ['required', 'numeric', 'gt:0'],
            'payment_amount' => ['required', 'numeric', 'gt:0'],
            'handling_fee' => ['required', 'numeric', 'min:0'],
            'is_pending' => ['nullable', 'boolean'],
        ]);

        DB::transaction(function () use ($data) {
            $currency = Currency::lockForUpdate()->findOrFail($data['currency_id']);
            $sourceAccount = Account::with('currency')->lockForUpdate()->findOrFail($data['source_account_id']);
            $targetAccount = Account::with('currency')->lockForUpdate()->findOrFail($data['target_account_id']);

            if ($sourceAccount->currency_id !== $currency->id) {
                throw ValidationException::withMessages([
                    'source_account_id' => 'Source account currency must match the selected currency to sell.',
                ]);
            }

            $quantity = (float) $data['quantity'];
            $paymentAmount = (float) $data['payment_amount'];
            $handlingFee = (float) $data['handling_fee'];
            $feeCurrency = strtoupper($targetAccount->currency->code);
            $isPending = !empty($data['is_pending']);

            // Calculate rate dynamically: rate = total received / quantity
            $rate = round($paymentAmount / $quantity, 4);

            if ((float) $sourceAccount->balance < $quantity) {
                throw ValidationException::withMessages([
                    'source_account_id' => 'Selected source account does not have enough currency balance.',
                ]);
            }

            $avgBuyRate = $currency->avg_buy_rate;

            if ($avgBuyRate === null) {
                throw ValidationException::withMessages([
                    'currency_id' => "Cannot sell {$currency->code} because there are no purchase or borrow transactions to define a cost basis.",
                ]);
            }

            $exchangeProfit = ($rate - $avgBuyRate) * $quantity;

            // Deduct from source account (the currency being sold) immediately
            $sourceAccount->update([
                'balance' => (float) $sourceAccount->balance - $quantity,
            ]);

            // Add to target account (only if not pending)
            if (!$isPending) {
                $targetAccount->update([
                    'balance' => (float) $targetAccount->balance + $paymentAmount + $handlingFee,
                ]);
            }

            Transaction::create([
                'type' => Transaction::TYPE_SELL,
                'agent_id' => $data['agent_id'] ?? null,
                'currency_id' => $currency->id,
                'quantity' => $quantity,
                'rate' => $rate,
                'payment_amount' => $paymentAmount,
                'payment_currency_id' => $targetAccount->currency_id,
                'payment_account_id' => $targetAccount->id, // Here target account receives the payment
                'handling_fee' => $handlingFee,
                'fee_currency' => $feeCurrency,
                'account_id' => $sourceAccount->id, // Source account from which currency is deducted
                'is_pending' => $isPending,
                'exchange_profit' => $exchangeProfit,
                'total_profit' => $exchangeProfit,
            ]);
        });

        return redirect()
            ->route('transactions.sell.create')
            ->with('success', 'Sell transaction saved successfully.');
    }

    public function edit(Transaction $transaction)
    {
        if ($transaction->type !== Transaction::TYPE_SELL) {
            abort(404);
        }

        return view('transactions.sell_edit', [
            'transaction' => $transaction,
            'agents' => Agent::orderBy('name')->get(),
            'currencies' => Currency::orderBy('code')->get(),
            'accounts' => Account::with('currency')->orderBy('name')->get(),
        ]);
    }

    public function update(Request $request, Transaction $transaction)
    {
        if ($transaction->type !== Transaction::TYPE_SELL) {
            abort(404);
        }

        $data = $request->validate([
            'agent_id' => ['nullable', 'exists:agents,id'],
            'currency_id' => ['required', 'exists:currencies,id'],
            'source_account_id' => ['required', 'exists:accounts,id'],
            'target_account_id' => ['required', 'exists:accounts,id'],
            'quantity' => ['required', 'numeric', 'gt:0'],
            'payment_amount' => ['required', 'numeric', 'gt:0'],
            'handling_fee' => ['required', 'numeric', 'min:0'],
            'is_pending' => ['nullable', 'boolean'],
        ]);

        DB::transaction(function () use ($data, $transaction) {
            // 1. Reverse old transaction
            $transaction->reverseBalanceEffects();

            // 2. Prepare new data
            $currency = Currency::lockForUpdate()->findOrFail($data['currency_id']);
            $sourceAccount = Account::with('currency')->lockForUpdate()->findOrFail($data['source_account_id']);
            $targetAccount = Account::with('currency')->lockForUpdate()->findOrFail($data['target_account_id']);

            if ($sourceAccount->currency_id !== $currency->id) {
                throw ValidationException::withMessages([
                    'source_account_id' => 'Source account currency must match the selected currency to sell.',
                ]);
            }

            $quantity = (float) $data['quantity'];
            $paymentAmount = (float) $data['payment_amount'];
            $handlingFee = (float) $data['handling_fee'];
            $feeCurrency = strtoupper($targetAccount->currency->code);
            $isPending = !empty($data['is_pending']);

            // Calculate rate dynamically
            $rate = round($paymentAmount / $quantity, 4);

            if ((float) $sourceAccount->balance < $quantity) {
                throw ValidationException::withMessages([
                    'source_account_id' => 'Selected source account does not have enough currency balance.',
                ]);
            }

            $avgBuyRate = $currency->avg_buy_rate;
            if ($avgBuyRate === null) {
                throw ValidationException::withMessages([
                    'currency_id' => "Cannot sell {$currency->code} because there are no purchase or borrow transactions to define a cost basis.",
                ]);
            }

            $exchangeProfit = ($rate - $avgBuyRate) * $quantity;

            // 3. Deduct from source account (the currency being sold) immediately
            $sourceAccount->update([
                'balance' => (float) $sourceAccount->balance - $quantity,
            ]);

            // 4. Add to target account (only if not pending)
            if (!$isPending) {
                $targetAccount->update([
                    'balance' => (float) $targetAccount->balance + $paymentAmount + $handlingFee,
                ]);
            }

            // 5. Update transaction record
            $transaction->update([
                'agent_id' => $data['agent_id'] ?? null,
                'currency_id' => $currency->id,
                'quantity' => $quantity,
                'rate' => $rate,
                'payment_amount' => $paymentAmount,
                'payment_currency_id' => $targetAccount->currency_id,
                'payment_account_id' => $targetAccount->id,
                'handling_fee' => $handlingFee,
                'fee_currency' => $feeCurrency,
                'account_id' => $sourceAccount->id,
                'is_pending' => $isPending,
                'exchange_profit' => $exchangeProfit,
                'total_profit' => $exchangeProfit,
            ]);
        });

        return redirect()
            ->route('reports.transactions')
            ->with('success', 'Sell transaction updated and balances recalculated successfully.');
    }
}
