<?php

namespace App\Services;

use App\Enums\RecordStatus;
use App\Models\Transaction;
use App\Models\User;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class UserBalanceService
{
    public function add(User $user, float $amount, User $admin): array
    {
        return $this->adjust($user, $amount, 'balance_add', $admin);
    }

    public function subtract(User $user, float $amount, User $admin): array
    {
        if ((float) $user->balance < $amount) {
            throw ValidationException::withMessages([
                'amount' => 'Insufficient balance. User has $'.number_format($user->balance, 2).' available.',
            ]);
        }

        return $this->adjust($user, -$amount, 'balance_subtract', $admin);
    }

    private function adjust(User $user, float $delta, string $type, User $admin): array
    {
        return DB::transaction(function () use ($user, $delta, $type, $admin) {
            $locked = User::query()->whereKey($user->id)->lockForUpdate()->firstOrFail();

            $balanceBefore = round((float) $locked->balance, 8);
            $balanceAfter = round($balanceBefore + $delta, 8);

            if ($balanceAfter < 0) {
                throw ValidationException::withMessages([
                    'amount' => 'Insufficient balance for this subtraction.',
                ]);
            }

            $locked->update(['balance' => $balanceAfter]);

            $actionLabel = $delta >= 0 ? 'added' : 'subtracted';
            $absAmount = abs($delta);

            Transaction::create([
                'user_id' => $locked->id,
                'type' => $type,
                'details' => sprintf(
                    'Admin %s $%s to balance by %s. Balance: $%s → $%s',
                    $actionLabel,
                    number_format($absAmount, 2, '.', ''),
                    $admin->name,
                    number_format($balanceBefore, 2, '.', ''),
                    number_format($balanceAfter, 2, '.', '')
                ),
                'amount' => $absAmount,
                'status' => RecordStatus::Approved,
            ]);

            return [
                'balance_before' => $balanceBefore,
                'balance_after' => $balanceAfter,
                'delta' => $delta,
            ];
        });
    }
}
