<?php
namespace App\Core;

use RuntimeException;
use Throwable;

class WithdrawalService {
    public static function process(int $requestId, string $targetStatus, int $adminId): array {
        $targetStatus = strtolower(trim($targetStatus));
        if (!in_array($targetStatus, ['approved','paid','rejected','cancelled'], true)) {
            return ['ok'=>false,'message'=>'Unsupported withdrawal status.'];
        }
        try {
            return Database::transaction(function() use ($requestId,$targetStatus,$adminId) {
                $request = Database::fetchOne('SELECT * FROM withdraw_requests WHERE id=? LIMIT 1 FOR UPDATE', [$requestId]);
                if (!$request) throw new RuntimeException('Withdrawal request not found.');
                $current = strtolower((string)($request['status'] ?? 'pending'));
                if ($current === $targetStatus) return ['ok'=>true,'message'=>'Withdrawal status is already ' . $targetStatus . '.'];
                if (in_array($current, ['paid','rejected','cancelled'], true)) throw new RuntimeException('A finalized withdrawal cannot be changed.');

                $userId = (int)$request['user_id'];
                $gross = round((float)$request['amount'], 2);
                $fee = round((float)$request['fee'], 2);
                $sourceWallet = (string)$request['wallet_type'];

                if ($current === 'pending' && in_array($targetStatus, ['approved','paid'], true)) {
                    if (!WalletService::debit($userId, 'withdraw', $gross, 'Withdrawal released', $requestId)) {
                        throw new RuntimeException('The withdrawal hold wallet does not contain the requested amount.');
                    }
                    if ($fee > 0) {
                        Database::execute('UPDATE admin_wallets SET balance=balance+?,updated_at=NOW() WHERE wallet_type="vat_tax_admin"', [$fee]);
                    }
                    Database::execute('UPDATE withdraw_requests SET status=?,approved_by=?,otp_verified_at=COALESCE(otp_verified_at,NOW()),processed_at=NOW(),updated_at=NOW() WHERE id=?', [$targetStatus,$adminId,$requestId]);
                } elseif ($current === 'pending' && in_array($targetStatus, ['rejected','cancelled'], true)) {
                    if (!WalletService::debit($userId, 'withdraw', $gross, 'Withdrawal hold released', $requestId)) {
                        throw new RuntimeException('The withdrawal hold wallet does not contain the requested amount.');
                    }
                    if (!WalletService::credit($userId, $sourceWallet, $gross, 'Rejected withdrawal returned', $requestId)) {
                        throw new RuntimeException('Could not return the withdrawal amount to the source wallet.');
                    }
                    Database::execute('UPDATE withdraw_requests SET status=?,approved_by=?,processed_at=NOW(),updated_at=NOW() WHERE id=?', [$targetStatus,$adminId,$requestId]);
                } elseif ($current === 'approved' && $targetStatus === 'paid') {
                    Database::execute('UPDATE withdraw_requests SET status="paid",approved_by=?,processed_at=COALESCE(processed_at,NOW()),updated_at=NOW() WHERE id=?', [$adminId,$requestId]);
                } else {
                    throw new RuntimeException('Invalid withdrawal status transition.');
                }

                Security::logActivity($adminId, 'withdrawal_status_changed', ['request_id'=>$requestId,'from'=>$current,'to'=>$targetStatus,'amount'=>$gross]);
                return ['ok'=>true,'message'=>'Withdrawal marked ' . $targetStatus . '.'];
            });
        } catch (Throwable $e) {
            return ['ok'=>false,'message'=>$e instanceof RuntimeException ? $e->getMessage() : 'Could not process the withdrawal.'];
        }
    }
}
