<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\BalanceLog;
use App\Models\IncomeHistory;
use App\Models\Withdraw;
use App\Support\WithdrawHistoryRecorder;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;

class WithdrawRequestController extends Controller
{
    // ✅ Pending Requests
    public function indexPending(Request $request)
    {
        return $this->renderWithdrawList($request, 'pending', 'admin.withdraw.pending');
    }

    // ✅ Approved Requests
    public function indexApproved(Request $request)
    {
        return $this->renderWithdrawList($request, 'approved', 'admin.withdraw.approved');
    }

    // ✅ Rejected Requests
    public function indexRejected(Request $request)
    {
        return $this->renderWithdrawList($request, 'rejected', 'admin.withdraw.rejected');
    }

    public function indexHistory(Request $request)
    {
        return $this->renderWithdrawList($request, 'all', 'admin.withdraw.history');
    }

    private function renderWithdrawList(Request $request, string $status, string $view)
    {
        $filters = $this->filtersFromRequest($request);

        $withdrawQuery = Withdraw::with('user', 'method', 'type', 'histories.admin')
            ->when($status !== 'all', fn (Builder $query) => $query->where('status', $status));

        $this->applyFilters($withdrawQuery, $filters);

        $withdraws = $withdrawQuery
            ->latest()
            ->get();

        return view($view, compact('withdraws', 'status'));
    }

    private function filtersFromRequest(Request $request): array
    {
        $fromDate = trim((string) $request->query('from_date', ''));
        $toDate = trim((string) $request->query('to_date', ''));

        $fromDate = preg_match('/^\d{4}-\d{2}-\d{2}$/', $fromDate) ? $fromDate : '';
        $toDate = preg_match('/^\d{4}-\d{2}-\d{2}$/', $toDate) ? $toDate : '';

        if ($fromDate !== '' && $toDate !== '' && $fromDate > $toDate) {
            [$fromDate, $toDate] = [$toDate, $fromDate];
        }

        return [
            'search' => trim((string) $request->query('search', '')),
            'from_date' => $fromDate,
            'to_date' => $toDate,
        ];
    }

    private function applyFilters(Builder $query, array $filters): void
    {
        if ($filters['search'] !== '') {
            $search = $filters['search'];
            $searchLike = '%' . str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $search) . '%';
            $requestId = $this->requestIdFromSearch($search);
            $hasTransactionId = Schema::hasColumn('withdraws', 'transaction_id');

            $query->where(function (Builder $withdrawQuery) use ($search, $searchLike, $requestId, $hasTransactionId) {
                $withdrawQuery->whereHas('user', function (Builder $userQuery) use ($search) {
                    $this->applyUserSearch($userQuery, $search);
                });

                if ($hasTransactionId) {
                    $withdrawQuery->orWhere('transaction_id', 'like', $searchLike);
                }

                if ($requestId !== null) {
                    $withdrawQuery->orWhere('id', $requestId);
                }

                $withdrawQuery->orWhere('number', 'like', $searchLike)
                    ->orWhereHas('method', function (Builder $methodQuery) use ($searchLike) {
                        $methodQuery->where('name', 'like', $searchLike);
                    })
                    ->orWhereHas('type', function (Builder $typeQuery) use ($searchLike) {
                        $typeQuery->where('name', 'like', $searchLike);
                    });
            });
        }

        if ($filters['from_date'] !== '') {
            $query->whereDate('created_at', '>=', $filters['from_date']);
        }

        if ($filters['to_date'] !== '') {
            $query->whereDate('created_at', '<=', $filters['to_date']);
        }
    }

    private function applyUserSearch(Builder $query, string $search): void
    {
        $searchLike = '%' . str_replace(['\\', '%', '_'], ['\\\\', '\\%', '\\_'], $search) . '%';

        $query->where('referral_code', 'like', $searchLike)
            ->orWhere('name', 'like', $searchLike)
            ->orWhere('mobile', 'like', $searchLike)
            ->orWhere('email', 'like', $searchLike);

        $userId = $this->requestIdFromSearch($search);
        if ($userId !== null) {
            $query->orWhere('id', $userId);
        }
    }

    private function requestIdFromSearch(string $search): ?int
    {
        $normalized = trim($search);
        $normalized = preg_replace('/^(#|wr-|withdraw-|request-)\s*/i', '', $normalized) ?? $normalized;

        return ctype_digit($normalized) ? (int) $normalized : null;
    }

    // ✅ Approve
    public function approve($id)
    {
        try {
            DB::transaction(function () use ($id) {
                $withdraw = Withdraw::with('user')->lockForUpdate()->findOrFail($id);

                if ($withdraw->status !== 'pending') {
                    throw new \RuntimeException('ALREADY_PROCESSED');
                }

                $fromStatus = $withdraw->status;
                $balance = $withdraw->user ? round((float) $withdraw->user->balance, 2) : null;

                $withdraw->status = 'approved';
                $withdraw->save();

                WithdrawHistoryRecorder::record(
                    withdraw: $withdraw,
                    event: 'approved',
                    fromStatus: $fromStatus,
                    toStatus: 'approved',
                    balanceBefore: $balance,
                    balanceAfter: $balance,
                    adminId: auth('admin')->id() ? (int) auth('admin')->id() : null,
                    note: 'অ্যাডমিন উইথড্র রিকোয়েস্ট approve করেছেন।',
                    metadata: [
                        'admin_id' => auth('admin')->id(),
                    ]
                );
            });
        } catch (\RuntimeException $e) {
            if ($e->getMessage() === 'ALREADY_PROCESSED') {
                return back()->with('error', 'এই রিকোয়েস্টটি ইতোমধ্যে প্রসেস করা হয়েছে।');
            }

            throw $e;
        }

        return back()->with('success', 'উইথড্র রিকোয়েস্ট অ্যাপ্রুভ করা হয়েছে।');
    }

    // ✅ Reject with Balance Refund
    public function reject($id)
    {
        try {
            DB::transaction(function () use ($id) {
                $withdraw = Withdraw::with('user')->lockForUpdate()->findOrFail($id);

                if ($withdraw->status !== 'pending') {
                    throw new \RuntimeException('ALREADY_PROCESSED');
                }

                $user = \App\Models\User::whereKey($withdraw->user_id)->lockForUpdate()->first();
                if (!$user) {
                    throw new \RuntimeException('USER_NOT_FOUND');
                }

                $fromStatus = $withdraw->status;
                $refundAmount = round((float) $withdraw->amount + (float) $withdraw->charge, 2);
                $beforeBalance = round((float) $user->balance, 2);
                $afterBalance = round($beforeBalance + $refundAmount, 2);

                $user->balance = $afterBalance;
                $user->save();

                $withdraw->status = 'rejected';
                $withdraw->save();

                BalanceLog::create([
                    'user_id' => $user->id,
                    'amount' => $refundAmount,
                    'type' => 'withdraw_reject_refund',
                    'previous_balance' => $beforeBalance,
                    'new_balance' => $afterBalance,
                ]);

                IncomeHistory::create([
                    'user_id' => $user->id,
                    'source' => 'withdraw_reject_refund',
                    'amount' => $refundAmount,
                    'description' => 'উইথড্র রিকোয়েস্ট #' . $withdraw->id . ' reject হওয়ায় ' . number_format($refundAmount, 2) . '৳ ব্যালেন্সে ফেরত দেওয়া হয়েছে।',
                    'previous_balance' => $beforeBalance,
                    'new_balance' => $afterBalance,
                ]);

                WithdrawHistoryRecorder::record(
                    withdraw: $withdraw,
                    event: 'rejected',
                    fromStatus: $fromStatus,
                    toStatus: 'rejected',
                    balanceBefore: $beforeBalance,
                    balanceAfter: $afterBalance,
                    adminId: auth('admin')->id() ? (int) auth('admin')->id() : null,
                    note: 'অ্যাডমিন উইথড্র রিকোয়েস্ট reject করেছেন এবং ব্যালেন্স refund হয়েছে।',
                    metadata: [
                        'admin_id' => auth('admin')->id(),
                        'refund_amount' => $refundAmount,
                    ]
                );
            });
        } catch (\RuntimeException $e) {
            if ($e->getMessage() === 'ALREADY_PROCESSED') {
                return back()->with('error', 'এই রিকোয়েস্টটি ইতোমধ্যে প্রসেস করা হয়েছে।');
            }

            if ($e->getMessage() === 'USER_NOT_FOUND') {
                return back()->with('error', 'ইউজার খুঁজে পাওয়া যায়নি।');
            }

            throw $e;
        } catch (\Throwable $e) {
            return back()->with('error', 'সমস্যা হয়েছে: ' . $e->getMessage());
        }

        return back()->with('success', 'উইথড্র রিকোয়েস্ট বাতিল করা হয়েছে এবং টাকা ইউজারের ব্যালেন্সে ফেরত দেয়া হয়েছে।');
    }
}
