<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use App\Traits\HotelScopeTrait;

class Guest extends Model
{
    use HasFactory, HotelScopeTrait;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'hotel_id', // ADDED
        'first_name',
        'last_name',
        'email',
        'phone',
        'address',
        'city',
        'country',
        'nationality',
        'id_type',
        'id_number',
        'date_of_birth',
        'gender',
        'preferences',
        'special_requests',
        'status',
        'loyalty_points',
        'is_blacklisted',
        'is_walkin_guest',
        'is_reservation_guest',
        'is_service_guest',
        'is_regular_guest',
        'blacklist_reason',
        'total_visits',
        'last_visit_date',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'date_of_birth' => 'date',
        'preferences' => 'array',
        'is_blacklisted' => 'boolean',
        'is_walkin_guest' => 'boolean',
        'is_reservation_guest' => 'boolean',
        'is_service_guest' => 'boolean',
        'is_regular_guest' => 'boolean',
        'loyalty_points' => 'integer',
        'total_visits' => 'integer',
        'last_visit_date' => 'date',
    ];

    /**
     * The accessors to append to the model's array form.
     *
     * @var array<int, string>
     */
    protected $appends = [
        'full_name',
        'current_reservation',
        'current_room',
        'guest_types_badges',
        'guest_types_array',
        'has_multiple_types',
        'service_statistics',
        'name',
        'total_service_spent',
        'favorite_service',
    ];

    /**
     * Boot the model.
     */
    protected static function boot()
    {
        parent::boot();
    }

    /**
     * Get the hotel that owns the guest.
     */
    public function hotel()
    {
        return $this->belongsTo(Hotel::class);
    }

    /**
     * Get the reservations for the guest.
     */
    public function reservations(): HasMany
    {
        return $this->hasMany(Reservation::class);
    }

    /**
     * Get the activities for the guest.
     */
    public function activities(): HasMany
    {
        return $this->hasMany(GuestActivity::class);
    }

    /**
     * Get the service requests for the guest.
     */
    public function serviceRequests(): HasMany
    {
        return $this->hasMany(ServiceRequest::class);
    }

    /**
     * Get services through service requests.
     */
    public function services()
    {
        return $this->hasManyThrough(
            Service::class,
            ServiceRequest::class,
            'guest_id',
            'id',
            'id',
            'service_id'
        );
    }

    /**
     * Get the current reservation for the guest.
     */
    public function getCurrentReservationAttribute()
    {
        return $this->reservations()
            ->where('status', 'checked_in')
            ->with('room')
            ->first();
    }

    /**
     * Get the current room for the guest.
     */
    public function getCurrentRoomAttribute()
    {
        $reservation = $this->current_reservation;
        return $reservation->room ?? null;
    }

    /**
     * Get the guest's full name.
     */
    public function getFullNameAttribute(): string
    {
        return trim("{$this->first_name} {$this->last_name}");
    }

    /**
     * Get the guest's name (alias for full_name for compatibility).
     */
    public function getNameAttribute(): string
    {
        return $this->full_name;
    }

    /**
     * Get guest types as badges HTML
     */
    public function getGuestTypesBadgesAttribute(): string
    {
        $badges = [];
        
        if ($this->is_walkin_guest) {
            $badges[] = '<span class="badge bg-blue-100 text-blue-800">Walk-in</span>';
        }
        
        if ($this->is_reservation_guest) {
            $badges[] = '<span class="badge bg-indigo-100 text-indigo-800">Reservation</span>';
        }
        
        if ($this->is_service_guest) {
            $badges[] = '<span class="badge bg-orange-100 text-orange-800">Service</span>';
        }
        
        if ($this->is_regular_guest) {
            $badges[] = '<span class="badge bg-purple-100 text-purple-800">Regular</span>';
        }
        
        if ($this->is_blacklisted) {
            $badges[] = '<span class="badge bg-red-100 text-red-800">Blacklisted</span>';
        }
        
        return implode(' ', $badges);
    }

    /**
     * Get guest types as array
     */
    public function getGuestTypesArrayAttribute(): array
    {
        $types = [];
        
        if ($this->is_walkin_guest) $types[] = 'walk_in';
        if ($this->is_reservation_guest) $types[] = 'reservation';
        if ($this->is_service_guest) $types[] = 'service';
        
        return $types;
    }

    /**
     * Check if guest has multiple types
     */
    public function getHasMultipleTypesAttribute(): bool
    {
        return count($this->guest_types_array) > 1;
    }

    /**
     * Calculate total visits (reservations + service requests)
     */
    public function calculateTotalVisits(): int
    {
        $reservationCount = $this->reservations()->count();
        $serviceCount = $this->serviceRequests()->count();
        
        return $reservationCount + $serviceCount;
    }

    /**
     * Update visit count and regular status
     */
    public function updateVisitCount(): self
    {
        $totalVisits = $this->calculateTotalVisits();
        
        $this->total_visits = $totalVisits;
        $this->last_visit_date = now();
        $this->updateRegularGuestStatus();
        
        return $this;
    }

    /**
     * Update regular guest status based on number of guest types
     */
    public function updateRegularGuestStatus(): self
    {
        $typeCount = 0;
        if ($this->is_walkin_guest) $typeCount++;
        if ($this->is_reservation_guest) $typeCount++;
        if ($this->is_service_guest) $typeCount++;
        
        // Guest becomes regular if they have 2 or more types
        $this->is_regular_guest = $typeCount >= 2;
        
        return $this;
    }

    /**
     * Mark guest as walk-in guest
     */
    public function markAsWalkin(): self
    {
        $this->is_walkin_guest = true;
        $this->updateVisitCount();
        $this->save();
        
        Log::info('Guest marked as walk-in', [
            'guest_id' => $this->id,
            'is_walkin' => $this->is_walkin_guest,
            'is_regular' => $this->is_regular_guest
        ]);
        
        return $this;
    }

    /**
     * Mark guest as reservation guest
     */
    public function markAsReservationGuest(): self
    {
        $this->is_reservation_guest = true;
        $this->updateVisitCount();
        $this->save();
        
        Log::info('Guest marked as reservation guest', [
            'guest_id' => $this->id,
            'is_reservation' => $this->is_reservation_guest,
            'is_regular' => $this->is_regular_guest
        ]);
        
        return $this;
    }

    /**
     * Mark guest as service guest - CRITICAL FIXED METHOD
     */
    public function markAsServiceGuest(): self
    {
        $this->is_service_guest = true;
        $this->updateVisitCount();
        $this->save();
        
        Log::info('Guest marked as service guest', [
            'guest_id' => $this->id,
            'is_service' => $this->is_service_guest,
            'is_regular' => $this->is_regular_guest,
            'total_types' => ($this->is_walkin_guest ? 1 : 0) + 
                            ($this->is_reservation_guest ? 1 : 0) + 
                            ($this->is_service_guest ? 1 : 0)
        ]);
        
        return $this;
    }

    /**
     * Clear guest type (if needed)
     */
    public function clearGuestType(string $type): self
    {
        switch ($type) {
            case 'walkin':
                $this->is_walkin_guest = false;
                break;
            case 'reservation':
                $this->is_reservation_guest = false;
                break;
            case 'service':
                $this->is_service_guest = false;
                break;
        }
        
        $this->updateRegularGuestStatus();
        $this->save();
        
        return $this;
    }

    /**
     * Reset all guest types
     */
    public function resetGuestTypes(): self
    {
        $this->is_walkin_guest = false;
        $this->is_reservation_guest = false;
        $this->is_service_guest = false;
        $this->is_regular_guest = false;
        $this->save();
        
        return $this;
    }

    /**
     * Get total spent on services
     */
    public function getTotalServiceSpentAttribute(): float
    {
        return (float) $this->serviceRequests()
            ->where('status', 'completed')
            ->sum('total_price');
    }

    /**
     * Get favorite service
     */
    public function getFavoriteServiceAttribute()
    {
        return $this->serviceRequests()
            ->select('service_id', DB::raw('count(*) as total'))
            ->with('service')
            ->groupBy('service_id')
            ->orderByDesc('total')
            ->first();
    }

    /**
     * Get service statistics
     */
    public function getServiceStatisticsAttribute(): array
    {
        $serviceRequests = $this->serviceRequests;
        
        return [
            'total_services' => $serviceRequests->count(),
            'total_spent' => $serviceRequests->sum('total_price'),
            'completed_services' => $serviceRequests->where('status', 'completed')->count(),
            'pending_services' => $serviceRequests->where('status', 'pending')->count(),
            'in_progress_services' => $serviceRequests->where('status', 'in_progress')->count(),
            'cancelled_services' => $serviceRequests->where('status', 'cancelled')->count(),
        ];
    }

    /**
     * Get recent service requests
     */
    public function getRecentServiceRequests($limit = 5)
    {
        return $this->serviceRequests()
            ->with('service')
            ->latest()
            ->limit($limit)
            ->get();
    }

    /**
     * Scope a query to only include blacklisted guests.
     */
    public function scopeBlacklisted($query)
    {
        return $query->where('is_blacklisted', true);
    }

    /**
     * Scope a query to search guests.
     */
    public function scopeSearch($query, $search)
    {
        return $query->where(function($q) use ($search) {
            $q->where('first_name', 'like', "%{$search}%")
              ->orWhere('last_name', 'like', "%{$search}%")
              ->orWhere('email', 'like', "%{$search}%")
              ->orWhere('phone', 'like', "%{$search}%")
              ->orWhere('id_number', 'like', "%{$search}%");
        });
    }

    /**
     * Scope a query to only include regular guests (more than 1 visit).
     */
    public function scopeRegular($query)
    {
        return $query->where('total_visits', '>', 1);
    }

    /**
     * Scope a query to only include walk-in guests.
     */
    public function scopeWalkIn($query)
    {
        return $query->where('is_walkin_guest', true);
    }

    /**
     * Scope a query to only include reservation guests.
     */
    public function scopeReservation($query)
    {
        return $query->where('is_reservation_guest', true);
    }

    /**
     * Scope a query to only include service guests.
     */
    public function scopeService($query)
    {
        return $query->where('is_service_guest', true);
    }

    /**
     * Scope a query to only include guests with multiple types.
     */
    public function scopeMultipleTypes($query)
    {
        return $query->where(function($q) {
            $q->where(function($sub) {
                $sub->where('is_walkin_guest', true)
                    ->where('is_reservation_guest', true);
            })->orWhere(function($sub) {
                $sub->where('is_walkin_guest', true)
                    ->where('is_service_guest', true);
            })->orWhere(function($sub) {
                $sub->where('is_reservation_guest', true)
                    ->where('is_service_guest', true);
            })->orWhere(function($sub) {
                $sub->where('is_walkin_guest', true)
                    ->where('is_reservation_guest', true)
                    ->where('is_service_guest', true);
            });
        });
    }

    /**
     * Scope a query to order guests by name.
     */
    public function scopeOrderByName($query)
    {
        return $query->orderBy('first_name')->orderBy('last_name');
    }

    /**
     * Scope a query to only include active guests.
     */
    public function scopeActive($query)
    {
        return $query->where('status', 'active');
    }

    /**
     * Scope a query to only include VIP guests.
     */
    public function scopeVip($query)
    {
        return $query->where('status', 'vip');
    }
}