<?php

namespace App\Services;

use App\Enums\CreditType;
use App\Models\CreditHistory;
use App\Models\User;
use Illuminate\Support\Facades\DB;

/**
 * Mengelola mutasi saldo credit secara atomik (RPD BR-13, NFR-04).
 *
 * Setiap perubahan saldo: update kolom `users.credit` + catat `credit_history`
 * dalam satu transaksi database agar konsisten.
 */
class CreditService
{
    /**
     * Tambah credit (In) — mis. konfirmasi billing lunas, refund campaign.
     *
     * @param  array{invoice?: ?string, keterangan?: ?string}  $meta
     */
    public function add(User $user, int $amount, array $meta = []): CreditHistory
    {
        return $this->mutate($user, $amount, CreditType::In, $meta);
    }

    /**
     * Kurangi credit (Out) — mis. pembuatan campaign.
     *
     * @param  array{invoice?: ?string, keterangan?: ?string}  $meta
     */
    public function subtract(User $user, int $amount, array $meta = []): CreditHistory
    {
        return $this->mutate($user, $amount, CreditType::Out, $meta);
    }

    /**
     * Apakah user memiliki saldo cukup?
     */
    public function hasEnough(User $user, int $amount): bool
    {
        return $user->credit >= $amount;
    }

    /**
     * Inti mutasi: update saldo + catat history dalam transaksi.
     *
     * @param  array{invoice?: ?string, keterangan?: ?string}  $meta
     */
    protected function mutate(User $user, int $amount, CreditType $jenis, array $meta): CreditHistory
    {
        return DB::transaction(function () use ($user, $amount, $jenis, $meta): CreditHistory {
            // Kunci baris user agar saldo tidak race-condition.
            $locked = User::whereKey($user->id)->lockForUpdate()->first();
            $locked->credit = $jenis === CreditType::In
                ? $locked->credit + $amount
                : $locked->credit - $amount;
            $locked->save();

            $history = CreditHistory::create([
                'invoice' => $meta['invoice'] ?? null,
                'tanggal' => now(),
                'keterangan' => $meta['keterangan'] ?? null,
                'credit' => $amount,
                'jenis' => $jenis,
                'user_id' => $locked->id,
            ]);

            // Sinkronkan instance yang dipakai pemanggil.
            $user->credit = $locked->credit;

            return $history;
        });
    }
}
