<?php

namespace App\Models;

use App\Services\TenantContext;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

use Illuminate\Database\Eloquent\Relations\HasMany;
use App\Traits\HotelScopeTrait;

class Service extends Model
{
    use HasFactory, HotelScopeTrait;

    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'services';

    /**
     * The attributes that are mass assignable.
     * Updated to match your database schema exactly
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'hotel_id',
        'service_category_id',
        'name',
        'description',
        'price',
        'duration',
        'is_active',
        'is_available',
        'image',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'price' => 'decimal:2',
        'is_active' => 'boolean',
        'is_available' => 'boolean',
        'duration' => 'integer',
    ];

    /**
     * The accessors to append to the model's array form.
     *
     * @var array<int, string>
     */
    protected $appends = [
        'formatted_price',
        'category_name',
        'total_revenue',
        'usage_count',
        'completed_count',
        'pending_count',
        'is_available_status',
    ];

    /**
     * ============================================================
     * RELATIONSHIPS
     * ============================================================
     */

    /**
     * Get the category that this service belongs to.
     */
    public function serviceCategory(): BelongsTo
    {
        return $this->belongsTo(ServiceCategory::class, 'service_category_id');
    }

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

    /**
     * ============================================================
     * SCOPES
     * ============================================================
     */

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

    /**
     * Scope a query to only include available services.
     */
    public function scopeAvailable($query)
    {
        return $query->where('is_available', true);
    }

    /**
     * Scope a query to filter by category ID.
     */
    public function scopeFilterByCategory($query, $categoryId = null)
    {
        if ($categoryId === null) {
            return $query;
        }
        
        return $query->where('service_category_id', $categoryId);
    }

    /**
     * Scope a query to filter by hotel.
     */
    public function scopeForHotel($query, $hotelId = null)
    {
        $hotelId = $hotelId ?? app(TenantContext::class)->hotelId();
        if ($hotelId) {
            return $query->where('hotel_id', $hotelId);
        }
        return $query;
    }

    /**
     * Scope a query to search services.
     */
    public function scopeSearch($query, $search)
    {
        if (empty($search)) {
            return $query;
        }
        
        return $query->where(function($q) use ($search) {
            $q->where('name', 'LIKE', "%{$search}%")
              ->orWhere('description', 'LIKE', "%{$search}%")
              ->orWhereHas('serviceCategory', function($q) use ($search) {
                  $q->where('name', 'LIKE', "%{$search}%");
              });
        });
    }

    /**
     * ============================================================
     * ACCESSORS
     * ============================================================
     */

    /**
     * Get formatted price.
     */
    public function getFormattedPriceAttribute(): string
    {
        $currency = setting('currency_symbol', 'UGX');
        return $currency . ' ' . number_format($this->price, 0);
    }

    /**
     * Get category display name through the relationship.
     */
    public function getCategoryNameAttribute(): ?string
    {
        return $this->serviceCategory?->name;
    }

    /**
     * Get available status with icon/text.
     */
    public function getIsAvailableStatusAttribute(): array
    {
        if (!$this->is_active) {
            return ['text' => 'Inactive', 'class' => 'bg-secondary', 'icon' => 'fas fa-ban'];
        }
        
        if ($this->is_available) {
            return ['text' => 'Available', 'class' => 'bg-success', 'icon' => 'fas fa-check-circle'];
        }
        
        return ['text' => 'Unavailable', 'class' => 'bg-warning text-dark', 'icon' => 'fas fa-clock'];
    }

    /**
     * ============================================================
     * AGGREGATES & CALCULATIONS
     * ============================================================
     */

    /**
     * Get total revenue from this service.
     */
    public function getTotalRevenueAttribute(): float
    {
        return (float) $this->serviceRequests()
            ->where('status', 'completed')
            ->sum('total_price');
    }

    /**
     * Get usage count (total number of service requests).
     */
    public function getUsageCountAttribute(): int
    {
        return $this->serviceRequests()->count();
    }

    /**
     * Get completed requests count.
     */
    public function getCompletedCountAttribute(): int
    {
        return $this->serviceRequests()
            ->where('status', 'completed')
            ->count();
    }

    /**
     * Get pending requests count.
     */
    public function getPendingCountAttribute(): int
    {
        return $this->serviceRequests()
            ->where('status', 'pending')
            ->count();
    }

    /**
     * Get in progress requests count.
     */
    public function getInProgressCountAttribute(): int
    {
        return $this->serviceRequests()
            ->where('status', 'in_progress')
            ->count();
    }

    /**
     * Get average rating for this service.
     */
    public function getAverageRatingAttribute(): float
    {
        return (float) $this->serviceRequests()
            ->whereNotNull('rating')
            ->avg('rating') ?? 0;
    }

    /**
     * Get formatted average rating.
     */
    public function getFormattedAverageRatingAttribute(): string
    {
        $avg = $this->average_rating;
        return number_format($avg, 1) . ' ★';
    }

    /**
     * ============================================================
     * BUSINESS LOGIC METHODS
     * ============================================================
     */

    /**
     * Toggle active status.
     */
    public function toggleActive(): self
    {
        $this->is_active = !$this->is_active;
        $this->save();
        
        return $this;
    }

    /**
     * Toggle available status.
     */
    public function toggleAvailable(): self
    {
        $this->is_available = !$this->is_available;
        $this->save();
        
        return $this;
    }

    /**
     * Check if service can be assigned (is active and available).
     */
    public function canBeAssigned(): bool
    {
        return $this->is_active && $this->is_available;
    }

    /**
     * Get service statistics for dashboard.
     */
    public function getStats(): array
    {
        return [
            'total_requests' => $this->usage_count,
            'completed_requests' => $this->completed_count,
            'pending_requests' => $this->pending_count,
            'in_progress_requests' => $this->in_progress_count,
            'total_revenue' => $this->total_revenue,
            'formatted_total_revenue' => $this->formatted_price,
            'average_rating' => $this->average_rating,
        ];
    }

    /**
     * ============================================================
     * STATIC METHODS
     * ============================================================
     */

    /**
     * Get services grouped by category.
     */
    public static function getGroupedByCategory()
    {
        return self::with('serviceCategory')
            ->active()
            ->available()
            ->get()
            ->groupBy(function($service) {
                return $service->serviceCategory->name ?? 'Uncategorized';
            });
    }

    /**
     * Get popular services (most requested).
     */
    public static function getPopular($limit = 5)
    {
        return self::withCount('serviceRequests')
            ->active()
            ->orderBy('service_requests_count', 'desc')
            ->limit($limit)
            ->get();
    }

    /**
     * Get service statistics for dashboard.
     */
    public static function getDashboardStats()
    {
        return [
            'total' => self::count(),
            'active' => self::where('is_active', true)->count(),
            'inactive' => self::where('is_active', false)->count(),
            'available' => self::where('is_available', true)->count(),
            'unavailable' => self::where('is_available', false)->count(),
            'with_requests' => self::has('serviceRequests')->count(),
        ];
    }

    /**
     * ============================================================
     * EVENTS
     * ============================================================
     */

    /**
     * The "booted" method of the model.
     */
    protected static function booted()
    {
        static::creating(function ($service) {
            if (empty($service->hotel_id)) {
                $ctx = app(TenantContext::class)->hotelId();
                if (! $ctx && auth()->check()) {
                    $ctx = auth()->user()->hotel_id ?? auth()->user()->hotel?->id;
                }
                if (! $ctx) {
                    throw new \RuntimeException('Cannot create service without a resolved hotel context.');
                }
                $service->hotel_id = $ctx;
            }
            
            // Set default values
            if (is_null($service->is_active)) {
                $service->is_active = true;
            }
            
            if (is_null($service->is_available)) {
                $service->is_available = true;
            }
        });

        static::deleting(function ($service) {
            // Prevent deletion if there are associated service requests
            if ($service->serviceRequests()->count() > 0) {
                throw new \Exception('Cannot delete service with associated requests.');
            }
        });
    }
}