<?php

namespace App\Modules\Wallet\Services;

use App\Core\Exceptions\InsufficientBalanceException;
use App\Core\Exceptions\ServiceException;
use App\Core\Traits\GeneratesReference;
use App\Models\Wallet;
use App\Models\WalletTransaction;
use App\Modules\Wallet\Interfaces\WalletRepositoryInterface;
use App\Modules\Wallet\Interfaces\WalletServiceInterface;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Collection;

class WalletService implements WalletServiceInterface
{
    use GeneratesReference;

    public function __construct(
        protected WalletRepositoryInterface $walletRepository
    ) {}

    public function getOrCreateWallet(string $userId): Wallet
    {
        $wallet = $this->walletRepository->findByUserId($userId);

        if (!$wallet) {
            $wallet = $this->walletRepository->createForUser($userId);
        }

        return $wallet;
    }

    public function getBalance(string $userId): float
    {
        $wallet = $this->getOrCreateWallet($userId);
        return $this->walletRepository->getBalance($wallet->id);
    }

    public function fundWallet(
        string $userId,
        float $amount,
        string $providerRef,
        array $metadata = []
    ): void {
        $wallet = $this->getOrCreateWallet($userId);

        $reference = self::generateReference('FND');

        $this->walletRepository->credit(
            $wallet->id,
            $amount,
            "Wallet funding via Paystack (Ref: {$providerRef})",
            $reference,
            'payment',
            null,
            array_merge($metadata, ['paystack_reference' => $providerRef])
        );
    }

    public function debitWallet(
        string $userId,
        float $amount,
        string $description,
        string $reference,
        ?string $relatedType = null,
        ?string $relatedId = null
    ): void {
        $wallet = $this->getOrCreateWallet($userId);

        $this->walletRepository->debit(
            $wallet->id,
            $amount,
            $description,
            $reference,
            $relatedType,
            $relatedId
        );
    }

    public function refundWallet(
        string $userId,
        float $amount,
        string $description,
        string $reference,
        ?string $relatedType = null,
        ?string $relatedId = null
    ): void {
        $wallet = $this->getOrCreateWallet($userId);

        $this->walletRepository->credit(
            $wallet->id,
            $amount,
            $description,
            $reference,
            $relatedType,
            $relatedId,
            null,
            true
        );
    }

    public function canDebit(string $userId, float $amount): bool
    {
        $wallet = $this->getOrCreateWallet($userId);
        return $this->walletRepository->canDebit($wallet->id, $amount);
    }

    public function getTransactions(
        string $userId,
        int $perPage = 15,
        ?string $type = null,
        ?string $fromDate = null,
        ?string $toDate = null
    ): LengthAwarePaginator {
        $wallet = $this->getOrCreateWallet($userId);
        return $this->walletRepository->getTransactions($wallet->id, $perPage, $type);
    }

    public function getStatement(
        string $userId,
        ?string $fromDate = null,
        ?string $toDate = null
    ): Collection {
        $wallet = $this->getOrCreateWallet($userId);
        return $this->walletRepository->getStatement($wallet->id, $fromDate, $toDate);
    }
}
