<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

#[Fillable([
    'booking_code', 'subscription_code', 'is_subscription', 'visits_per_period', 'visits_used',
    'billing_period', 'current_period_start', 'current_period_end', 'next_billing_date', 'auto_renew',
    'subscription_status',
    'customer_id', 'partner_id', 'service_id', 'area_id',
    'customer_name', 'customer_phone', 'address', 'pincode', 'lat', 'lng',
    'scheduled_date', 'scheduled_slot', 'notes',
    'amount_paise', 'tax_paise', 'total_paise',
    'status', 'payment_status', 'payment_method', 'transaction_id',
    'start_otp', 'start_otp_verified_at', 'completion_otp', 'completion_otp_verified_at',
    'accepted_at', 'started_at', 'completed_at', 'cancelled_at',
])]
class Booking extends Model
{
    use HasFactory;

    protected $casts = [
        'scheduled_date' => 'date',
        'current_period_start' => 'date',
        'current_period_end' => 'date',
        'next_billing_date' => 'date',
        'is_subscription' => 'boolean',
        'auto_renew' => 'boolean',
        'accepted_at' => 'datetime',
        'started_at' => 'datetime',
        'completed_at' => 'datetime',
        'cancelled_at' => 'datetime',
        'start_otp_verified_at' => 'datetime',
        'completion_otp_verified_at' => 'datetime',
    ];

    public function customer(): BelongsTo
    {
        return $this->belongsTo(User::class, 'customer_id');
    }

    public function partner(): BelongsTo
    {
        return $this->belongsTo(PartnerProfile::class, 'partner_id');
    }

    public function service(): BelongsTo
    {
        return $this->belongsTo(Service::class);
    }

    public function area(): BelongsTo
    {
        return $this->belongsTo(Area::class);
    }

    public function photos(): HasMany
    {
        return $this->hasMany(BookingPhoto::class);
    }

    public function rating(): \Illuminate\Database\Eloquent\Relations\HasOne
    {
        return $this->hasOne(Rating::class)->latestOfMany();
    }

    public function statusLogs(): HasMany
    {
        return $this->hasMany(BookingStatusLog::class);
    }

    public function visits(): HasMany
    {
        return $this->hasMany(SubscriptionVisit::class)->orderBy('scheduled_date');
    }

    public function getTotalRupeesAttribute(): float
    {
        return round($this->total_paise / 100, 2);
    }

    public function getAmountRupeesAttribute(): float
    {
        return round($this->amount_paise / 100, 2);
    }

    public function getTaxRupeesAttribute(): float
    {
        return round($this->tax_paise / 100, 2);
    }

    public function getStatusColorAttribute(): string
    {
        if ($this->is_subscription) {
            return match ($this->subscription_status) {
                'active' => 'green',
                'paused' => 'gold',
                'cancelled', 'expired' => 'red',
                default => 'grey',
            };
        }
        return match ($this->status) {
            'pending' => 'gold',
            'accepted', 'on_the_way', 'arrived' => 'blue',
            'in_progress' => 'orange',
            'completed' => 'green',
            'cancelled', 'rejected' => 'red',
            default => 'grey',
        };
    }

    public function getDisplayStatusAttribute(): string
    {
        if ($this->is_subscription) {
            return match ($this->subscription_status) {
                'active' => 'Active',
                'paused' => 'Paused',
                'cancelled' => 'Cancelled',
                'expired' => 'Expired',
                default => 'Pending',
            };
        }
        return ucwords(str_replace('_', ' ', $this->status));
    }

    public function getUpcomingVisitAttribute(): ?SubscriptionVisit
    {
        return $this->visits()->where('status', 'scheduled')->where('scheduled_date', '>=', now()->toDateString())->orderBy('scheduled_date')->first();
    }

    public function getVisitsRemainingAttribute(): int
    {
        return max(0, ($this->visits_per_period ?? 1) - ($this->visits_used ?? 0));
    }

    public static function generateCode(): string
    {
        $letters = strtoupper(substr(str_replace(['+', '/', '='], '', base64_encode(random_bytes(4))), 0, 6));
        return 'BFK-' . $letters;
    }

    public static function generateSubscriptionCode(): string
    {
        $letters = strtoupper(substr(str_replace(['+', '/', '='], '', base64_encode(random_bytes(4))), 0, 6));
        return 'SUB-' . $letters;
    }
}
