<?php

namespace App\Models;

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

/**
 * TrainingPackage Model
 *
 * Represents a training program/package that can be offered to users.
 * Contains information about the training content, duration, fees, and capacity.
 *
 * @property int $id
 * @property string $name
 * @property string|null $description
 * @property string|null $learning_objectives
 * @property string|null $prerequisites
 * @property int $duration_hours
 * @property int $duration_days
 * @property int $capacity
 * @property float $fee_amount
 * @property string $currency
 * @property bool $is_free
 * @property string $certificate_format
 * @property bool $generates_certificate
 * @property string $status
 * @property bool $is_public
 * @property bool $requires_approval
 * @property int|null $category_id
 * @property array|null $tags
 * @property string|null $featured_image
 * @property int|null $created_by
 * @property int|null $updated_by
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 * @property \Illuminate\Support\Carbon|null $deleted_at
 */
class TrainingPackage extends Model
{
    use HasFactory, SoftDeletes;

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

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'description',
        'learning_objectives',
        'prerequisites',
        'duration_hours',
        'duration_days',
        'capacity',
        'fee_amount',
        'currency',
        'is_free',
        'certificate_format',
        'generates_certificate',
        'status',
        'is_public',
        'requires_approval',
        'category_id',
        'tags',
        'featured_image',
        'created_by',
        'updated_by',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'tags' => 'array',
        'is_free' => 'boolean',
        'generates_certificate' => 'boolean',
        'is_public' => 'boolean',
        'requires_approval' => 'boolean',
        'fee_amount' => 'decimal:2',
        'duration_hours' => 'integer',
        'duration_days' => 'integer',
        'capacity' => 'integer',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
        'deleted_at' => 'datetime',
    ];

    /**
     * The model's default values for attributes.
     *
     * @var array
     */
    protected $attributes = [
        'duration_hours' => 0,
        'duration_days' => 0,
        'capacity' => 50,
        'fee_amount' => 0.00,
        'currency' => 'UGX',
        'is_free' => false,
        'certificate_format' => 'portrait',
        'generates_certificate' => true,
        'status' => 'draft',
        'is_public' => true,
        'requires_approval' => true,
    ];

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

    /**
     * Get the category that this package belongs to.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function category(): BelongsTo
    {
        return $this->belongsTo(TrainingCategory::class, 'category_id');
    }

    /**
     * Get the user who created this package.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    /**
     * Get the user who last updated this package.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function updater(): BelongsTo
    {
        return $this->belongsTo(User::class, 'updated_by');
    }

    /**
     * Get all sessions for this training package.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function sessions(): HasMany
    {
        return $this->hasMany(TrainingSession::class, 'training_package_id');
    }

    /**
     * Get all registrations for this training package.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function registrations(): HasMany
    {
        return $this->hasMany(TrainingRegistration::class, 'training_package_id');
    }

    /**
     * Get all certificates issued for this training package.
     *
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function certificates(): HasMany
    {
        return $this->hasMany(TrainingCertificate::class, 'training_package_id');
    }

    /**
     * Get all trainers who have ever been assigned to sessions of this package.
     * Uses a hasManyThrough-style approach via the sessions relationship.
     *
     * @return \Illuminate\Database\Eloquent\Collection
     */
    public function getTrainersAttribute()
    {
        return \App\Models\User::whereHas('trainedSessions', function ($q) {
            $q->where('training_package_id', $this->id);
        })->get();
    }

    // =========================================================================
    // QUERY SCOPES
    // =========================================================================

    /**
     * Scope to get only active packages.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeActive($query)
    {
        return $query->where('status', 'active');
    }

    /**
     * Scope to get only public packages.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePublic($query)
    {
        return $query->where('is_public', true);
    }

    /**
     * Scope to get only free packages.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeFree($query)
    {
        return $query->where('is_free', true);
    }

    /**
     * Scope to get only paid packages.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopePaid($query)
    {
        return $query->where('is_free', false);
    }

    /**
     * Scope to get packages by status.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param string $status
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeWithStatus($query, string $status)
    {
        return $query->where('status', $status);
    }

    // =========================================================================
    // HELPER METHODS
    // =========================================================================

    /**
     * Check if the package is active.
     *
     * @return bool
     */
    public function isActive(): bool
    {
        return $this->status === 'active';
    }

    /**
     * Check if the package requires payment.
     *
     * @return bool
     */
    public function requiresPayment(): bool
    {
        return !$this->is_free && $this->fee_amount > 0;
    }

    /**
     * Get the current enrollment count.
     *
     * @return int
     */
    public function getEnrollmentCount(): int
    {
        return $this->registrations()
            ->whereIn('status', ['approved', 'completed'])
            ->count();
    }

    /**
     * Get the remaining capacity.
     *
     * @return int
     */
    public function getRemainingCapacity(): int
    {
        return max(0, $this->capacity - $this->getEnrollmentCount());
    }

    /**
     * Check if the package has available capacity.
     *
     * @return bool
     */
    public function hasCapacity(): bool
    {
        return $this->getRemainingCapacity() > 0;
    }

    /**
     * Check if the package has sessions scheduled.
     *
     * @return bool
     */
    public function hasSessions(): bool
    {
        return $this->sessions()->exists();
    }

    /**
     * Get upcoming sessions.
     *
     * @return \Illuminate\Database\Eloquent\Collection
     */
    public function getUpcomingSessions()
    {
        return $this->sessions()
            ->where('session_date', '>=', now()->toDateString())
            ->where('status', 'scheduled')
            ->orderBy('session_date')
            ->orderBy('start_time')
            ->get();
    }

    /**
     * Get formatted duration string.
     *
     * @return string
     */
    public function getFormattedDuration(): string
    {
        $parts = [];
        
        if ($this->duration_days > 0) {
            $parts[] = $this->duration_days . ' ' . str('day')->plural($this->duration_days);
        }
        
        if ($this->duration_hours > 0) {
            $parts[] = $this->duration_hours . ' ' . str('hour')->plural($this->duration_hours);
        }
        
        return !empty($parts) ? implode(', ', $parts) : 'Not specified';
    }

    /**
     * Get formatted fee string.
     *
     * @return string
     */
    public function getFormattedFee(): string
    {
        if ($this->is_free) {
            return 'Free';
        }
        
        return number_format($this->fee_amount, 0) . ' ' . $this->currency;
    }

    /**
     * Activate the package.
     *
     * @return bool
     */
    public function activate(): bool
    {
        return $this->update(['status' => 'active']);
    }

    /**
     * Deactivate the package.
     *
     * @return bool
     */
    public function deactivate(): bool
    {
        return $this->update(['status' => 'inactive']);
    }
}
