<?php

namespace App\Models;

use App\Exceptions\PaymentMissingDataException;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Collection;

/**
 * @property int $id
 * @property int $client_id
 * @property int|null $provider_id
 * @property int $address_id
 * @property \Illuminate\Support\Carbon $date
 * @property string $period_type
 * @property string $schedule_type
 * @property string $start_time
 * @property string $end_time
 * @property string $status
 * @property numeric $total_amount
 * @property string $code
 * @property bool $code_verified
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 * @property \Illuminate\Support\Carbon|null $deleted_at
 * @property bool|null $offers_meal
 * @property string|null $cancel_text
 * @property string|null $cancelled_by
 * @property-read \App\Models\Address $address
 * @property-read \App\Models\Client $client
 * @property-read \App\Models\CustomSchedule|null $customSchedule
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ScheduleProposal> $proposals
 * @property-read int|null $proposals_count
 * @property-read \App\Models\Provider|null $provider
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\ScheduleRefuse> $refuses
 * @property-read int|null $refuses_count
 * @property-read \Illuminate\Database\Eloquent\Collection<int, \App\Models\Review> $reviews
 * @property-read int|null $reviews_count
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule newModelQuery()
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule newQuery()
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule onlyTrashed()
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule query()
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereAddressId($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereCancelText($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereCancelledBy($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereClientId($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereCode($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereCodeVerified($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereCreatedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereDate($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereDeletedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereEndTime($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereId($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereOffersMeal($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule wherePeriodType($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereProviderId($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereScheduleType($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereStartTime($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereStatus($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereTotalAmount($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule whereUpdatedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule withTrashed(bool $withTrashed = true)
 * @method static \Illuminate\Database\Eloquent\Builder<static>|Schedule withoutTrashed()
 * @mixin \Eloquent
 */
class Schedule extends Model
{
    use HasFactory, SoftDeletes;

    protected $fillable = [
        'client_id',
        'provider_id',
        'address_id',
        'date',
        'period_type',
        'schedule_type',
        'start_time',
        'end_time',
        'status',
        'total_amount',
        'code',
        'code_verified',
        'offers_meal',
        'cancel_text',
        'cancelled_by',
    ];

    protected $casts = [
        'date'          => 'date',
        'code_verified' => 'boolean',
        'total_amount'  => 'decimal:2',
        'offers_meal'   => 'boolean',
    ];

    public function client()
    {
        return $this->belongsTo(Client::class)->select(
            'id',
            'user_id',
            'document',
            'average_rating',
            'gateway_customer_id',
            'gateway_customer_code',
            'profile_media_id',
        );
    }

    public function provider()
    {
        return $this->belongsTo(Provider::class);
    }

    //

    public function address()
    {
        return $this->belongsTo(Address::class, 'address_id')->select('id', 'district');
    }

    public function customSchedule()
    {
        return $this->hasOne(CustomSchedule::class)->select('id', 'service_type_id', 'min_price', 'max_price', 'schedule_id');
    }

    public function proposals()
    {
        return $this->hasMany(ScheduleProposal::class);
    }

    public function refuses()
    {
        return $this->hasMany(ScheduleRefuse::class);
    }

    public function reviews()
    {
        return $this->hasMany(Review::class);
    }

    public function getSpecialitiesAttribute(): Collection
    {
        if ($this->schedule_type !== 'custom') {
            return collect();
        }

        return $this->customSchedule?->specialities
            ->sortBy('description')
            ->map(fn(CustomScheduleSpeciality $speciality) => [
                'id'          => $speciality->id,
                'description' => $speciality->description,
            ])
            ->values() ?? collect();
    }

    //

    public function ensureCustomerPhone(?string $fallbackPhone = null): void
    {
        $phone  = $this->client?->user?->phone ?? $fallbackPhone;
        $digits = preg_replace('/\D+/', '', (string) $phone) ?? '';

        if (strlen($digits) >= 10) {
            return;
        }

        throw new PaymentMissingDataException(
            'Voce precisa cadastrar um numero de celular valido no seu perfil para concluir o pagamento.'
        );
    }
}
