<?php
// app/Models/Subscription.php

namespace App\Models;

use App\Models\Base\TenantModel;
use App\Models\Admin\AdminHotelSubscriptionHistory;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Carbon\Carbon;

class Subscription extends TenantModel
{
    use HasFactory;

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

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'hotel_id',
        'subscription_number',
        'plan_name',
        'plan_price',
        'billing_cycle',
        'start_date',
        'end_date',
        'trial_start_date',
        'trial_end_date',
        'status',
        'max_rooms',
        'max_users',
        'enabled_modules',
        'notes',
        'cancelled_at'
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array
     */
    protected $casts = [
        'plan_price' => 'decimal:2',
        'start_date' => 'datetime',
        'end_date' => 'datetime',
        'trial_start_date' => 'datetime',
        'trial_end_date' => 'datetime',
        'cancelled_at' => 'datetime',
        'max_rooms' => 'integer',
        'max_users' => 'integer',
        'enabled_modules' => 'array',
        'created_at' => 'datetime',
        'updated_at' => 'datetime'
    ];

    /**
     * The accessors to append to the model's array form.
     *
     * @var array
     */
    protected $appends = [
        'days_remaining',
        'is_expiring_soon',
        'usage_percentage',
        'formatted_price',
        'plan_details'
    ];

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

        // When subscription is created, ensure it has a subscription number
        static::creating(function ($subscription) {
            if (empty($subscription->subscription_number)) {
                $subscription->subscription_number = static::generateSubscriptionNumber();
            }
            
            // Set default max_rooms based on plan if not set
            if (empty($subscription->max_rooms) && !empty($subscription->plan_name)) {
                $subscription->max_rooms = static::getDefaultRoomsForPlan($subscription->plan_name);
            }
            
            // Set default max_users based on plan if not set
            if (empty($subscription->max_users) && !empty($subscription->plan_name)) {
                $subscription->max_users = static::getDefaultUsersForPlan($subscription->plan_name);
            }
            
            // Set default dates if not provided
            if (empty($subscription->start_date)) {
                $subscription->start_date = now();
            }
            
            if (empty($subscription->end_date) && $subscription->billing_cycle) {
                $subscription->end_date = static::calculateEndDate($subscription->start_date, $subscription->billing_cycle);
            }
        });

        // When subscription is created, log the action
        static::created(function ($subscription) {
            if (class_exists(AdminHotelSubscriptionHistory::class)) {
                try {
                    AdminHotelSubscriptionHistory::create([
                        'subscription_id' => $subscription->id,
                        'hotel_id' => $subscription->hotel_id,
                        'action' => 'created',
                        'new_values' => json_encode($subscription->toArray()),
                        'performed_by' => auth()->id()
                    ]);
                } catch (\Exception $e) {
                    \Log::warning('Could not create subscription history: ' . $e->getMessage());
                }
            }
        });

        // When subscription is updated, sync with hotel and log
        static::updated(function ($subscription) {
            $subscription->syncWithHotel();
            
            if (class_exists(AdminHotelSubscriptionHistory::class)) {
                try {
                    AdminHotelSubscriptionHistory::create([
                        'subscription_id' => $subscription->id,
                        'hotel_id' => $subscription->hotel_id,
                        'action' => 'updated',
                        'old_values' => json_encode($subscription->getOriginal()),
                        'new_values' => json_encode($subscription->getChanges()),
                        'performed_by' => auth()->id()
                    ]);
                } catch (\Exception $e) {
                    \Log::warning('Could not create subscription history: ' . $e->getMessage());
                }
            }
        });

        // When subscription is deleted, log the action
        static::deleted(function ($subscription) {
            if (class_exists(AdminHotelSubscriptionHistory::class)) {
                try {
                    AdminHotelSubscriptionHistory::create([
                        'subscription_id' => $subscription->id,
                        'hotel_id' => $subscription->hotel_id,
                        'action' => 'deleted',
                        'old_values' => json_encode($subscription->toArray()),
                        'performed_by' => auth()->id()
                    ]);
                } catch (\Exception $e) {
                    \Log::warning('Could not create subscription history: ' . $e->getMessage());
                }
            }
        });
    }

    // ==================== RELATIONSHIPS ====================

    /**
     * Relationship with hotel
     */
    public function hotel()
    {
        return $this->belongsTo(Hotel::class, 'hotel_id');
    }

    /**
     * Relationship with payments
     */
    public function payments()
    {
        return $this->hasMany(SubscriptionPayment::class, 'subscription_id');
    }

    /**
     * Relationship with history - FIXED with proper import
     */
    public function history()
    {
        return $this->hasMany(AdminHotelSubscriptionHistory::class, 'subscription_id');
    }

    // ==================== SYNC METHODS ====================

    /**
     * Sync subscription data with hotel
     */
    public function syncWithHotel()
    {
        $hotel = $this->hotel;
        
        if (!$hotel) {
            return false;
        }
        
        $hotel->package = $this->plan_name;
        $hotel->monthly_price = $this->plan_price;
        $hotel->billing_cycle = $this->billing_cycle;
        $hotel->max_rooms = $this->max_rooms;
        $hotel->max_users = $this->max_users;
        $hotel->status = $this->status;
        
        if ($this->status === 'active') {
            $hotel->subscription_ends_at = $this->end_date;
        } elseif ($this->status === 'trial') {
            $hotel->trial_ends_at = $this->trial_end_date;
            $hotel->subscription_starts_at = $this->trial_end_date;
        }
        
        if ($this->enabled_modules) {
            $hotel->enabled_modules = $this->enabled_modules;
        }
        
        $hotel->save();
        
        return true;
    }

    // ==================== ACCESSORS ====================

    /**
     * Get days remaining in subscription
     */
    public function getDaysRemainingAttribute()
    {
        $date = null;
        
        if ($this->status === 'trial' && $this->trial_end_date) {
            $date = $this->trial_end_date;
        } elseif ($this->status === 'active' && $this->end_date) {
            $date = $this->end_date;
        }
        
        return $date ? now()->diffInDays(Carbon::parse($date), false) : null;
    }

    /**
     * Get trial days remaining
     */
    public function getTrialDaysRemainingAttribute()
    {
        if ($this->status !== 'trial' || !$this->trial_end_date) {
            return null;
        }
        
        return now()->diffInDays(Carbon::parse($this->trial_end_date), false);
    }

    /**
     * Check if subscription is expiring soon
     */
    public function getIsExpiringSoonAttribute()
    {
        $days = $this->days_remaining;
        return $days !== null && $days <= 7 && $days >= 0;
    }

    /**
     * Check if subscription is expired
     */
    public function getIsExpiredAttribute()
    {
        $days = $this->days_remaining;
        return $days !== null && $days < 0;
    }

    /**
     * Get usage percentage
     */
    public function getUsagePercentageAttribute()
    {
        if (!$this->hotel) {
            return [
                'rooms' => 0,
                'users' => 0,
                'rooms_used' => 0,
                'users_used' => 0,
                'rooms_available' => $this->max_rooms ?? 0,
                'users_available' => $this->max_users ?? 0
            ];
        }
        
        $roomCount = $this->hotel->rooms()->count();
        $userCount = $this->hotel->users()->count();
        
        $roomPercentage = $this->max_rooms > 0 
            ? round(($roomCount / $this->max_rooms) * 100, 2) 
            : 0;
            
        $userPercentage = $this->max_users > 0 
            ? round(($userCount / $this->max_users) * 100, 2) 
            : 0;
            
        return [
            'rooms' => $roomPercentage,
            'users' => $userPercentage,
            'rooms_used' => $roomCount,
            'users_used' => $userCount,
            'rooms_available' => max(0, $this->max_rooms - $roomCount),
            'users_available' => max(0, $this->max_users - $userCount)
        ];
    }

    /**
     * Get formatted price
     */
    public function getFormattedPriceAttribute()
    {
        return number_format($this->plan_price, 0) . ' UGX';
    }

    /**
     * Get plan details as array
     */
    public function getPlanDetailsAttribute()
    {
        return [
            'name' => ucfirst($this->plan_name),
            'price' => $this->formatted_price,
            'price_raw' => $this->plan_price,
            'rooms' => $this->max_rooms,
            'users' => $this->max_users,
            'cycle' => ucfirst($this->billing_cycle)
        ];
    }

    /**
     * Get status badge class
     */
    public function getStatusBadgeClassAttribute()
    {
        $daysLeft = $this->days_remaining;
        
        if ($this->status === 'active' && $daysLeft !== null && $daysLeft <= 7 && $daysLeft >= 0) {
            return 'badge-expiring';
        }
        
        if ($this->status === 'active' && $daysLeft !== null && $daysLeft < 0) {
            return 'badge-expired';
        }
        
        return match($this->status) {
            'active' => 'badge-active',
            'trial' => 'badge-trial',
            'suspended' => 'badge-suspended',
            'expired' => 'badge-expired',
            'cancelled' => 'badge-expired',
            default => 'badge-secondary',
        };
    }

    /**
     * Get status text
     */
    public function getStatusTextAttribute()
    {
        $daysLeft = $this->days_remaining;
        
        if ($this->status === 'active' && $daysLeft !== null && $daysLeft <= 7 && $daysLeft >= 0) {
            return 'Expiring Soon';
        }
        
        if ($this->status === 'active' && $daysLeft !== null && $daysLeft < 0) {
            return 'Expired';
        }
        
        return ucfirst($this->status);
    }

    // ==================== STATIC HELPERS ====================

    /**
     * Calculate end date based on start date and billing cycle
     */
    public static function calculateEndDate($startDate, $billingCycle)
    {
        $start = Carbon::parse($startDate);
        
        return match($billingCycle) {
            'monthly' => $start->copy()->addMonth(),
            'quarterly' => $start->copy()->addMonths(3),
            'yearly' => $start->copy()->addYear(),
            default => $start->copy()->addMonth(),
        };
    }

    /**
     * Get default rooms for plan
     */
    public static function getDefaultRoomsForPlan($plan)
    {
        return match($plan) {
            'silver' => 20,
            'gold' => 40,
            'platinum' => 60,
            'custom' => 100,
            default => 20,
        };
    }

    /**
     * Get default users for plan
     */
    public static function getDefaultUsersForPlan($plan)
    {
        return match($plan) {
            'silver' => 2,
            'gold' => 5,
            'platinum' => 10,
            'custom' => 20,
            default => 2,
        };
    }

    /**
     * Get default price for plan
     */
    public static function getDefaultPriceForPlan($plan)
    {
        return match($plan) {
            'silver' => 150000,
            'gold' => 350000,
            'platinum' => 500000,
            'custom' => 0,
            default => 150000,
        };
    }

    /**
     * Generate a unique subscription number
     */
    public static function generateSubscriptionNumber()
    {
        $prefix = 'SUB';
        $year = date('Y');
        $month = date('m');
        
        $lastSubscription = self::whereYear('created_at', $year)
            ->whereMonth('created_at', $month)
            ->orderBy('id', 'desc')
            ->first();
        
        if ($lastSubscription && $lastSubscription->subscription_number) {
            $lastNumber = intval(substr($lastSubscription->subscription_number, -4));
            $newNumber = str_pad($lastNumber + 1, 4, '0', STR_PAD_LEFT);
        } else {
            $newNumber = '0001';
        }
        
        return "{$prefix}-{$year}{$month}-{$newNumber}";
    }

    // ==================== SCOPES ====================

    /**
     * Scope for active subscriptions
     */
    public function scopeActive($query)
    {
        return $query->where('status', 'active');
    }

    /**
     * Scope for trial subscriptions
     */
    public function scopeTrial($query)
    {
        return $query->where('status', 'trial');
    }

    /**
     * Scope for expiring soon subscriptions
     */
    public function scopeExpiringSoon($query, $days = 7)
    {
        return $query->where('status', 'active')
            ->where('end_date', '<=', now()->addDays($days))
            ->where('end_date', '>', now());
    }

    /**
     * Scope for expired subscriptions
     */
    public function scopeExpired($query)
    {
        return $query->where('status', 'active')
            ->where('end_date', '<', now());
    }

    /**
     * Scope for suspended subscriptions
     */
    public function scopeSuspended($query)
    {
        return $query->where('status', 'suspended');
    }

    /**
     * Scope for cancelled subscriptions
     */
    public function scopeCancelled($query)
    {
        return $query->where('status', 'cancelled');
    }

    /**
     * Scope for a specific hotel
     */
    public function scopeForHotel($query, $hotelId)
    {
        return $query->where('hotel_id', $hotelId);
    }

    /**
     * Scope for a specific plan
     */
    public function scopeOfPlan($query, $plan)
    {
        return $query->where('plan_name', $plan);
    }

    /**
     * Scope for a specific billing cycle
     */
    public function scopeWithBillingCycle($query, $cycle)
    {
        return $query->where('billing_cycle', $cycle);
    }

    /**
     * Scope to get latest subscription for each hotel
     */
    public function scopeLatestPerHotel($query)
    {
        return $query->whereIn('id', function($q) {
            $q->selectRaw('MAX(id)')
              ->from('subscriptions')
              ->groupBy('hotel_id');
        });
    }
}