<?php

namespace App\Repositories\Eloquent;

use App\Models\Booking;
use App\Repositories\Interfaces\BookingRepositoryInterface;

class BookingRepository extends BaseRepository implements BookingRepositoryInterface
{
    /**
     * BookingRepository constructor.
     */
    public function __construct(Booking $model)
    {
        parent::__construct($model);
    }

    public function findForUpdate(int $id): ?Booking
    {
        return $this->model->newQuery()->whereKey($id)->lockForUpdate()->first();
    }

    public function getUpcomingBooking($professionalData, $dateToday)
    {
        return $this->model->where('professional_id', $professionalData->id)
            ->where('date', '>=', $dateToday)
            ->where('status', '=', 'accepted')
            ->get();
    }

    public function getBookingByDate($professionalId, $date)
    {
        return $this->model->where('professional_id', $professionalId)
            ->where('date', $date)
            ->whereIn('status', ['pending', 'accepted'])
            ->when(\Illuminate\Support\Facades\Schema::hasColumn('bookings', 'payment_due_at'), function ($query) {
                $query->where(function ($query) {
                    $query->where('payment_status', 'paid')
                        ->orWhereNull('payment_due_at')
                        ->orWhere('payment_due_at', '>', now());
                });
            })
            ->when(\Illuminate\Support\Facades\DB::transactionLevel() > 0, fn ($query) => $query->lockForUpdate())
            ->get();
    }

    public function getReminderCandidates(array $dates)
    {
        return $this->model
            ->with(['client.profile', 'professional.user.profile'])
            ->where('type', 'appointment')
            ->where('status', 'accepted')
            ->where('payment_status', 'paid')
            ->whereNull('reminder_sent_at')
            ->whereIn('date', $dates)
            ->get();
    }

    public function getUnreleasedEarnings(int $professionalId)
    {
        return $this->model->with(['client.profile'])
            ->where('professional_id', $professionalId)
            ->where('payment_status', 'paid')
            ->whereNotNull('consultation_closed_at')
            ->whereNull('professional_payout_id')
            ->orderByDesc('consultation_closed_at')
            ->get();
    }

    public function getUnpaidExpirationCandidates(string $latestDate)
    {
        return $this->model->with(['client.profile', 'professional.user.profile'])
            ->where('type', 'appointment')
            ->whereIn('status', ['pending', 'accepted'])
            ->where(fn ($query) => $query->whereNull('payment_status')->orWhere('payment_status', '!=', 'paid'))
            ->whereNull('consultation_started_at')
            ->whereNull('consultation_closed_at')
            ->where(fn ($query) => $query->whereDate('date', '<=', $latestDate)
                ->orWhere('payment_due_at', '<=', now()))
            ->get();
    }

    public function expireUnpaidBooking(int $bookingId): bool
    {
        return $this->model->newQuery()->whereKey($bookingId)
            ->where('type', 'appointment')
            ->whereIn('status', ['pending', 'accepted'])
            ->where(fn ($query) => $query->whereNull('payment_status')->orWhere('payment_status', '!=', 'paid'))
            ->whereNull('consultation_started_at')->whereNull('consultation_closed_at')
            ->update(['status' => 'expired']) === 1;
    }
}
