<?php

namespace App\Http\Controllers\Admin;

use App\Enums\WithdrawalRequestStatus;
use App\Http\Controllers\Controller;
use App\Models\WithdrawalRequest;
use App\Support\InvestmentLedger;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;
use Inertia\Response;

class WithdrawalRequestManageController extends Controller
{
    /**
     * Cola de solicitudes y vistas recientes.
     */
    public function index(Request $request): Response
    {
        $tab = $request->query('tab', 'solicitudes');
        if (! in_array($tab, ['solicitudes', 'historial'], true)) {
            $tab = 'solicitudes';
        }

        $pending = WithdrawalRequest::query()
            ->where('status', WithdrawalRequestStatus::Pending)
            ->with([
                'investment:id,user_id,txid,capital_balance,amount,status',
                'requester:id,first_name,last_name,email',
            ])
            ->orderBy('created_at')
            ->get()
            ->map(fn (WithdrawalRequest $row): array => self::mapRequestRow($row));

        $recent = WithdrawalRequest::query()
            ->whereIn('status', [WithdrawalRequestStatus::Approved, WithdrawalRequestStatus::Rejected])
            ->with([
                'investment:id,user_id,txid',
                'requester:id,first_name,last_name,email',
                'processor:id,first_name,last_name',
            ])
            ->orderByDesc('processed_at')
            ->limit(80)
            ->get()
            ->map(fn (WithdrawalRequest $row): array => self::mapRequestRow($row));

        return Inertia::render('admin/withdrawal-requests', [
            'tab' => $tab,
            'pending' => $pending,
            'recent' => $recent,
            'history_rows' => WithdrawalHistoryController::ledgerRows()->values()->all(),
        ]);
    }

    /**
     * @return array<string, mixed>
     */
    private static function mapRequestRow(WithdrawalRequest $row): array
    {
        $withdrawable = InvestmentLedger::totalWithdrawableForUser((int) $row->user_id);

        return [
            'id' => $row->id,
            'investment_id' => $row->investment_id,
            'amount_usd' => number_format((float) $row->amount, 2, '.', ''),
            'fee_total_usd' => number_format((float) $row->fee_total, 2, '.', ''),
            'net_amount_usd' => $row->net_amount !== null
                ? number_format((float) $row->net_amount, 2, '.', '')
                : number_format(max(0, (float) $row->amount - (float) $row->fee_total), 2, '.', ''),
            'status' => $row->status->value,
            'created_at' => $row->created_at?->toIso8601String(),
            'processed_at' => $row->processed_at?->toIso8601String(),
            'admin_note' => $row->admin_note,
            'txid' => 'Balance usuario',
            'investor_name' => trim(
                ($row->requester?->first_name ?? '').' '.($row->requester?->last_name ?? ''),
            ) !== '' ? trim(
                ($row->requester?->first_name ?? '').' '.($row->requester?->last_name ?? ''),
            ) : '—',
            'investor_email' => $row->requester?->email,
            'withdrawable_balance_usd' => number_format($withdrawable, 2, '.', ''),
            'capital_at_request_usd' => number_format($withdrawable, 2, '.', ''),
            'processed_by_label' => trim(
                ($row->processor?->first_name ?? '').' '.($row->processor?->last_name ?? ''),
            ) !== '' ? trim(
                ($row->processor?->first_name ?? '').' '.($row->processor?->last_name ?? ''),
            ) : '—',
            'destination_network' => $row->destination_currency_network,
            'destination_address' => $row->destination_address,
            'destination_label' => $row->destination_label,
            'payout_txid' => $row->payout_txid,
            'requester_note' => $row->requester_note,
        ];
    }

    /**
     * Aprueba solicitud y genera línea en el ledger contra el capital vigente.
     */
    public function approve(Request $request, WithdrawalRequest $withdrawalRequest): RedirectResponse
    {
        $validated = $request->validate([
            'payout_txid' => ['required', 'string', 'max:191'],
        ]);

        $payoutTxid = trim($validated['payout_txid']);

        if ($payoutTxid === '') {
            throw ValidationException::withMessages([
                'payout_txid' => ['Introduce el TXID del envío on-chain.'],
            ]);
        }

        try {
            DB::transaction(function () use ($request, $withdrawalRequest, $payoutTxid): void {
                $lockedRequest = WithdrawalRequest::query()
                    ->whereKey($withdrawalRequest->id)
                    ->lockForUpdate()
                    ->firstOrFail();

                if ($lockedRequest->status !== WithdrawalRequestStatus::Pending) {
                    throw ValidationException::withMessages([
                        'request' => ['La solicitud ya no está pendiente.'],
                    ]);
                }

                InvestmentLedger::applyUserBalanceWithdrawal(
                    (int) $lockedRequest->user_id,
                    (float) $lockedRequest->amount,
                    $lockedRequest->id,
                );

                $lockedRequest->update([
                    'status' => WithdrawalRequestStatus::Approved,
                    'payout_txid' => $payoutTxid,
                    'processed_by' => $request->user()->id,
                    'processed_at' => now(),
                ]);
            });
        } catch (ValidationException $validationException) {
            return redirect()
                ->back()
                ->withErrors($validationException->errors());
        }

        Inertia::flash('toast', [
            'type' => 'success',
            'message' => 'Solicitud aprobada y retiro aplicado al balance del usuario.',
        ]);

        return redirect()->route('admin.withdrawals.requests.index');
    }

    /**
     * Rechaza solicitud sin tocar capital.
     */
    public function reject(Request $request, WithdrawalRequest $withdrawalRequest): RedirectResponse
    {
        $validated = $request->validate([
            'admin_note' => ['nullable', 'string', 'max:2000'],
        ]);

        try {
            DB::transaction(function () use ($request, $validated, $withdrawalRequest): void {
                $locked = WithdrawalRequest::query()
                    ->whereKey($withdrawalRequest->id)
                    ->lockForUpdate()
                    ->firstOrFail();

                if ($locked->status !== WithdrawalRequestStatus::Pending) {
                    throw ValidationException::withMessages([
                        'request' => ['La solicitud ya no está pendiente.'],
                    ]);
                }

                $locked->update([
                    'status' => WithdrawalRequestStatus::Rejected,
                    'admin_note' => $validated['admin_note'] ?? $locked->admin_note,
                    'processed_by' => $request->user()->id,
                    'processed_at' => now(),
                ]);
            });
        } catch (ValidationException $validationException) {
            return redirect()
                ->back()
                ->withErrors($validationException->errors());
        }

        Inertia::flash('toast', [
            'type' => 'success',
            'message' => 'Solicitud rechazada.',
        ]);

        return redirect()->route('admin.withdrawals.requests.index');
    }
}
