<?php

namespace App\Http\Livewire;

use App\Models\Notification;
use App\Models\User;
use App\Models\Withdrawal;
use Illuminate\Support\Facades\DB;
use Livewire\Component;
use Livewire\WithPagination;

class Withdrawals extends Component
{
    use WithPagination;

    protected $paginationTheme = 'bootstrap';

    public $transaction_search;
    public $transaction_type;
    public $withdrawal_id;
    public $note;
    public $decision_amount;
    public $decision_usd;
    public $selectedWithdrawals = [];
    public $selectPage = false;
    public $bulkAction = '';

    public function render()
    {
        $withdrawals = $this->withdrawalsQuery()->paginate(15);

        $selectedWithdrawal = $this->withdrawal_id
            ? Withdrawal::with(['user', 'faceVerifications.duplicateOfUser'])->find($this->withdrawal_id)
            : null;

        return view('livewire.withdrawals', compact('withdrawals', 'selectedWithdrawal'));
    }

    public function model($id)
    {
        $withdrawal = Withdrawal::findOrFail($id);
        $this->withdrawal_id = $withdrawal->id;
        $this->decision_amount = $withdrawal->amount;
        $this->decision_usd = coins_to_usd($withdrawal->amount);
        $this->dispatchBrowserEvent('open-withdrawal-modal');
    }

    public function updatingTransactionSearch(): void
    {
        $this->resetPage();
        $this->clearBulkSelection();
    }

    public function updatingTransactionType(): void
    {
        $this->resetPage();
        $this->clearBulkSelection();
    }

    public function updatedSelectPage($value): void
    {
        $this->selectedWithdrawals = $value
            ? $this->currentPageWithdrawalIds()
            : [];
    }

    public function updatedSelectedWithdrawals(): void
    {
        $pageIds = collect($this->currentPageWithdrawalIds());
        $selectedIds = collect($this->selectedWithdrawals)->map(fn($id) => (string) $id);

        $this->selectPage = $pageIds->isNotEmpty() && $pageIds->diff($selectedIds)->isEmpty();
    }

    public function updatingPage(): void
    {
        $this->clearBulkSelection();
    }

    public function applyBulkAction(): void
    {
        $ids = collect($this->selectedWithdrawals)->filter()->map(fn($id) => (int) $id)->unique()->values();

        if ($ids->isEmpty()) {
            session()->flash('error', 'Select at least one cashout request first.');
            return;
        }

        $withdrawals = Withdrawal::with('user')->whereKey($ids)
            ->where('status', 'pending')
            ->where('verification_status', 'approved')
            ->get();

        if ($withdrawals->isEmpty()) {
            session()->flash('error', 'Only pending cashout requests can be changed in bulk.');
            return;
        }

        if ($this->bulkAction === 'approve') {
            foreach ($withdrawals as $withdrawal) {
                $withdrawal->update(['status' => 'approved']);
                Notification::create([
                    'user_id' => $withdrawal->user->id,
                    'title' => 'Withdrawal Approved',
                    'message' => 'Your '.format_coins_as_usd($withdrawal->amount).' cashout has been approved.',
                ]);
            }
            session()->flash('success', 'Selected pending requests approved.');
        } elseif ($this->bulkAction === 'reject') {
            foreach ($withdrawals as $withdrawal) {
                DB::transaction(function () use ($withdrawal) {
                    $locked = Withdrawal::whereKey($withdrawal->id)->lockForUpdate()->firstOrFail();
                    if ($locked->status !== 'pending') return;
                    $locked->update(['status' => 'rejected']);
                    $locked->user()->lockForUpdate()->firstOrFail()->increment('current_points', (float) $locked->amount);
                    Notification::create([
                        'user_id' => $locked->user_id,
                        'title' => 'Your withdrawal has been rejected',
                        'message' => 'Your cashout was rejected and '.number_format($locked->amount, 0).' coins were returned.',
                    ]);
                }, 3);
            }
            session()->flash('success', 'Selected pending requests rejected and refunded.');
        } else {
            session()->flash('error', 'Choose a bulk action.');
            return;
        }

        $this->bulkAction = '';
        $this->selectedWithdrawals = [];
        $this->selectPage = false;
    }

    public function approve()
    {
        $withdrawal = Withdrawal::with('user')->findOrFail($this->withdrawal_id);

        if ($withdrawal->status !== 'pending') {
            return redirect()->back()->with(['error' => 'Only pending cashout requests can be approved.']);
        }

        if ($withdrawal->verification_status !== 'approved') {
            return redirect()->back()->with(['error' => 'This cashout must pass face review before payment approval.']);
        }

        $amount = round(max(0, (float) $this->decision_usd) * coins_per_usd(), 2);
        $originalAmount = (float) $withdrawal->amount;
        $difference = $originalAmount - $amount;

        if ($difference > 0) {
            $withdrawal->user->current_points += $difference;
            $withdrawal->user->save();
        }

        if ($difference < 0) {
            $extra = abs($difference);
            if ($withdrawal->user->current_points < $extra) {
                return redirect()->back()->with(['error' => 'The user does not have enough remaining balance for the increased approval amount.']);
            }

            $withdrawal->user->current_points -= $extra;
            $withdrawal->user->save();
        }

        $withdrawal->update([
            'status' => 'approved',
            'amount' => $amount,
        ]);

        Notification::create([
            'user_id' => $withdrawal->user->id,
            'title' => 'Withdrawal Approved',
            'message' => 'Your '.format_coins_as_usd($amount).' cashout has been approved.',
        ]);

        return redirect()->back()->with(['success' => 'Transaction approved successfully!']);
    }

    public function reject()
    {
        $withdrawal = Withdrawal::with('user')->findOrFail($this->withdrawal_id);

        if ($withdrawal->status !== 'pending') {
            return redirect()->back()->with(['error' => 'Only pending cashout requests can be rejected.']);
        }


        if ($withdrawal->verification_status !== 'approved') {
            return redirect()->back()->with(['error' => 'Review this cashout face check before changing its payment status.']);
        }

        $originalAmount = (float) $withdrawal->amount;
        $amount = max(0, (float) $this->decision_amount);

        $withdrawal->update([
            'status' => 'rejected',
            'amount' => $amount,
        ]);

        $withdrawal->user->current_points += $originalAmount;
        $withdrawal->user->save();

        Notification::create([
            'user_id' => $withdrawal->user->id,
            'title' => 'Your withdrawal has been rejected',
            'message' => 'Your withdrawal has been rejected by admin. Please contact us for more information.',
        ]);

        return redirect()->back()->with(['success' => 'Transaction rejected successfully!']);
    }

//    public function refund()
//    {
//        $withdrawal = Withdrawal::find($this->withdrawal_id);
//
//        $withdrawal->update([
//            'status' => 3,
//            'note' => $this->note
//        ]);
//
//        $withdrawal->user->current_points += $withdrawal->points;
//        $withdrawal->user->save();
//
//        Notification::create([
//            'user_id' => $withdrawal->user->id,
//            'title' => 'Your withdrawal has been refunded',
//            'message' => 'Your withdrawal has been refunded by admin. Please contact us for more information.',
//        ]);
//
//        return redirect()->back()->with(['success' => 'Transaction refunded successfully!']);
//    }

    private function withdrawalsQuery()
    {
        return Withdrawal::with(['user', 'faceVerifications' => fn ($query) => $query->latest()])
            ->where('verification_status', 'approved')
            ->when($this->transaction_type, function ($query, $transaction_type) {
                if ($transaction_type === '0') {
                    return $query;
                }

                return $query->where('status', $transaction_type);
            })->when($this->transaction_search, function ($query, $transaction_search) {
                $user = User::where('username', 'LIKE', "%$transaction_search%")
                    ->orWhere('email', 'LIKE', "%$transaction_search%")
                    ->pluck('id')
                    ->toArray();

                return $query->whereIn('user_id', $user);
            })->orderBy('created_at', 'desc');
    }

    private function currentPageWithdrawalIds(): array
    {
        return $this->withdrawalsQuery()
            ->paginate(15)
            ->pluck('id')
            ->map(fn($id) => (string) $id)
            ->all();
    }

    private function clearBulkSelection(): void
    {
        $this->selectedWithdrawals = [];
        $this->selectPage = false;
    }
}
