<?php

namespace App\Services;

use App\Models\User;
use App\Models\Voucher;
use App\Models\VoucherRedemption;
use Illuminate\Support\Facades\DB;
use RuntimeException;

class VoucherService
{
    public function __construct(private WalletService $wallets) {}

    public function redeem(User $user, string $code): VoucherRedemption
    {
        $normalizedCode = strtoupper(trim($code));

        return DB::transaction(function () use ($user, $normalizedCode) {
            $voucher = Voucher::where('code', $normalizedCode)->lockForUpdate()->first();

            if (! $voucher || ! $voucher->is_active) {
                throw new RuntimeException('Voucher is not available.');
            }

            if ($voucher->starts_at && $voucher->starts_at->isFuture()) {
                throw new RuntimeException('Voucher is not active yet.');
            }

            if ($voucher->ends_at && $voucher->ends_at->isPast()) {
                throw new RuntimeException('Voucher has expired.');
            }

            if ($voucher->usage_limit && $voucher->used_count >= $voucher->usage_limit) {
                throw new RuntimeException('Voucher usage limit has been reached.');
            }

            if ($voucher->once_per_user && VoucherRedemption::where('voucher_id', $voucher->id)->where('user_id', $user->id)->exists()) {
                throw new RuntimeException('Voucher was already used by this account.');
            }

            $wallet = $this->wallets->ensureWallet($user, $voucher->currency_code);

            $redemption = VoucherRedemption::create([
                'voucher_id' => $voucher->id,
                'user_id' => $user->id,
                'wallet_id' => $wallet->id,
                'amount_minor' => $voucher->amount_minor,
                'snapshot' => [
                    'code' => $voucher->code,
                    'name_ar' => $voucher->name_ar,
                    'currency_code' => $voucher->currency_code,
                    'amount_minor' => $voucher->amount_minor,
                ],
            ]);

            $this->wallets->credit(
                $wallet,
                $voucher->amount_minor,
                'voucher_redeem',
                'Voucher '.$voucher->code.' redeemed',
                VoucherRedemption::class,
                $redemption->id,
                ['voucher_code' => $voucher->code],
            );

            $voucher->increment('used_count');

            return $redemption;
        });
    }
}
