<?php

namespace App\Modules\Transactions\Repositories;

use App\Core\Repositories\BaseRepository;
use App\Models\Transaction;
use App\Modules\Transactions\Interfaces\TransactionRepositoryInterface;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\Collection;

class TransactionRepository extends BaseRepository implements TransactionRepositoryInterface
{
    public function __construct(Transaction $model)
    {
        parent::__construct($model);
    }

    public function create(array $data): Transaction
    {
        return $this->model->create($data);
    }

    public function findByReference(string $reference): ?Transaction
    {
        return $this->model->where('reference', $reference)->first();
    }

    public function findByUser(
        string $userId,
        int $perPage = 15,
        ?string $type = null,
        ?string $status = null
    ): LengthAwarePaginator {
        $query = $this->model->where('user_id', $userId)
            ->orderBy('created_at', 'desc');

        if ($type) {
            $query->where('type', $type);
        }

        if ($status) {
            $query->where('status', $status);
        }

        return $query->paginate($perPage);
    }

    public function updateStatus(string $id, string $status, ?array $providerResponse = null): Transaction
    {
        $transaction = $this->findOrFail($id);

        $data = ['status' => $status];

        if ($status === 'processing') {
            $data['processed_at'] = now();
        } elseif (in_array($status, ['successful', 'failed', 'refunded', 'cancelled'])) {
            $data['completed_at'] = now();
        }

        if ($providerResponse) {
            $data['provider_response'] = $providerResponse;
        }

        $transaction->update($data);
        return $transaction->fresh();
    }

    public function updateProviderReference(string $id, string $providerReference): Transaction
    {
        $transaction = $this->findOrFail($id);
        $transaction->update(['provider_reference' => $providerReference]);
        return $transaction->fresh();
    }

    public function markSuccessful(string $id, array $providerResponse, ?array $tokenData = null): Transaction
    {
        $transaction = $this->findOrFail($id);

        $data = [
            'status' => 'successful',
            'provider_response' => $providerResponse,
            'completed_at' => now(),
        ];

        if ($tokenData) {
            $data['token_data'] = $tokenData;
        }

        $transaction->update($data);
        return $transaction->fresh();
    }

    public function markFailed(string $id, string $reason, array $providerResponse): Transaction
    {
        $transaction = $this->findOrFail($id);
        $transaction->update([
            'status' => 'failed',
            'failure_reason' => $reason,
            'provider_response' => $providerResponse,
            'completed_at' => now(),
        ]);
        return $transaction->fresh();
    }

    public function findByProviderReference(string $providerReference): ?Transaction
    {
        return $this->model->where('provider_reference', $providerReference)->first();
    }

    public function getStats(string $userId): array
    {
        $query = $this->model->where('user_id', $userId);

        return [
            'total' => (clone $query)->count(),
            'successful' => (clone $query)->where('status', 'successful')->count(),
            'failed' => (clone $query)->where('status', 'failed')->count(),
            'pending' => (clone $query)->where('status', 'pending')->count(),
            'total_amount' => (clone $query)->where('status', 'successful')->sum('total_amount'),
            'total_fees' => (clone $query)->where('status', 'successful')->sum('fee'),
            'today_count' => (clone $query)->whereDate('created_at', today())->count(),
            'today_amount' => (clone $query)->whereDate('created_at', today())->where('status', 'successful')->sum('total_amount'),
        ];
    }

    public function getRecentTransactions(string $userId, int $limit = 5): Collection
    {
        return $this->model->where('user_id', $userId)
            ->orderBy('created_at', 'desc')
            ->limit($limit)
            ->get();
    }
}
