<?php

namespace App\Models\Mentorship;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Str;

class Programme extends Model
{
    use HasFactory, SoftDeletes;

    /**
     * The table associated with the model.
     */
    protected $table = 'mentorship_programmes';

    /**
     * The attributes that are mass assignable.
     */
    protected $fillable = [
        'title',
        'slug',
        'description',
        'objectives',
        'requirements',
        'target_audience',
        'category_id',
        'is_free',
        'fee_amount',
        'currency',
        'fee_description',
        'certificate_enabled',
        'certificate_orientation',
        'certificate_template',
        'duration_weeks',
        'sessions_count',
        'max_mentees',
        'max_mentors',
        'programme_type',
        'session_type',
        'venue',
        'is_active',
        'is_featured',
        'registration_start',
        'registration_end',
        'programme_start',
        'programme_end',
        'featured_image',
        'gallery_images',
        'banner_image',
        'meta_title',
        'meta_description',
        'created_by',
        'updated_by',
    ];

    /**
     * The attributes that should be cast.
     */
    protected $casts = [
        'is_free' => 'boolean',
        'certificate_enabled' => 'boolean',
        'is_active' => 'boolean',
        'is_featured' => 'boolean',
        'fee_amount' => 'decimal:2',
        'duration_weeks' => 'integer',
        'sessions_count' => 'integer',
        'max_mentees' => 'integer',
        'max_mentors' => 'integer',
        'applications_count' => 'integer',
        'assignments_count' => 'integer',
        'completions_count' => 'integer',
        'registration_start' => 'datetime',
        'registration_end' => 'datetime',
        'programme_start' => 'datetime',
        'programme_end' => 'datetime',
        'gallery_images' => 'array',
    ];

    /**
     * The "booted" method of the model.
     */
    protected static function booted(): void
    {
        static::creating(function (self $programme) {
            if (empty($programme->slug)) {
                $programme->slug = Str::slug($programme->title);
            }
        });

        static::updating(function (self $programme) {
            if ($programme->isDirty('title') && empty($programme->slug)) {
                $programme->slug = Str::slug($programme->title);
            }
        });
    }

    /*
    |--------------------------------------------------------------------------
    | Relationships
    |--------------------------------------------------------------------------
    */

    /**
     * Get the category of this programme.
     */
    public function category()
    {
        return $this->belongsTo(Category::class, 'category_id');
    }

    /**
     * Get the applications for this programme.
     */
    public function applications()
    {
        return $this->hasMany(Application::class, 'programme_id');
    }

    /**
     * Get the assignments for this programme.
     */
    public function assignments()
    {
        return $this->hasMany(Assignment::class, 'programme_id');
    }

    /**
     * Get the sessions for this programme.
     */
    public function sessions()
    {
        return $this->hasMany(Session::class, 'programme_id');
    }

    /**
     * Get the certificates for this programme.
     */
    public function certificates()
    {
        return $this->hasMany(Certificate::class, 'programme_id');
    }

    /**
     * Get the payments for this programme.
     */
    public function payments()
    {
        return $this->hasMany(Payment::class, 'programme_id');
    }

    /**
     * Get the user who created this programme.
     */
    public function creator()
    {
        return $this->belongsTo(\App\Models\User::class, 'created_by');
    }

    /**
     * Get the user who last updated this programme.
     */
    public function updater()
    {
        return $this->belongsTo(\App\Models\User::class, 'updated_by');
    }

    /*
    |--------------------------------------------------------------------------
    | Scopes
    |--------------------------------------------------------------------------
    */

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

    /**
     * Scope to get only featured programmes.
     */
    public function scopeFeatured($query)
    {
        return $query->where('is_featured', true);
    }

    /**
     * Scope to get free programmes.
     */
    public function scopeFree($query)
    {
        return $query->where('is_free', true);
    }

    /**
     * Scope to get paid programmes.
     */
    public function scopePaid($query)
    {
        return $query->where('is_free', false);
    }

    /**
     * Scope to get programmes with open registration.
     */
    public function scopeOpenForRegistration($query)
    {
        return $query->where(function ($q) {
            $q->whereNull('registration_start')
                ->orWhere('registration_start', '<=', now());
        })->where(function ($q) {
            $q->whereNull('registration_end')
                ->orWhere('registration_end', '>=', now());
        });
    }

    /**
     * Scope to filter by category.
     */
    public function scopeInCategory($query, $categoryId)
    {
        return $query->where('category_id', $categoryId);
    }

    /**
     * Scope to filter by session type.
     */
    public function scopeBySessionType($query, $type)
    {
        return $query->where('session_type', $type);
    }

    /*
    |--------------------------------------------------------------------------
    | Accessors & Mutators
    |--------------------------------------------------------------------------
    */

    /**
     * Get the formatted fee.
     */
    public function getFormattedFeeAttribute(): string
    {
        if ($this->is_free) {
            return 'Free';
        }

        return number_format($this->fee_amount, 2) . ' ' . $this->currency;
    }

    /**
     * Check if registration is currently open.
     */
    public function getIsRegistrationOpenAttribute(): bool
    {
        if (!$this->is_active) {
            return false;
        }

        if ($this->registration_start && $this->registration_start->isFuture()) {
            return false;
        }

        if ($this->registration_end && $this->registration_end->isPast()) {
            return false;
        }

        return true;
    }

    /**
     * Check if the programme is currently running.
     */
    public function getIsRunningAttribute(): bool
    {
        if (!$this->is_active) {
            return false;
        }

        if ($this->programme_start && $this->programme_start->isFuture()) {
            return false;
        }

        if ($this->programme_end && $this->programme_end->isPast()) {
            return false;
        }

        return true;
    }

    /**
     * Get the duration in a human-readable format.
     */
    public function getDurationTextAttribute(): string
    {
        if (!$this->duration_weeks) {
            return 'Flexible duration';
        }

        if ($this->duration_weeks < 4) {
            return $this->duration_weeks . ' week' . ($this->duration_weeks > 1 ? 's' : '');
        }

        $months = round($this->duration_weeks / 4);
        return $months . ' month' . ($months > 1 ? 's' : '');
    }

    /*
    |--------------------------------------------------------------------------
    | Helper Methods
    |--------------------------------------------------------------------------
    */

    /**
     * Check if user can apply to this programme.
     */
    public function canApply(?\App\Models\User $user = null): bool
    {
        if (!$this->is_registration_open) {
            return false;
        }

        // Check if user already applied (if logged in)
        if ($user) {
            $existingApplication = $this->applications()
                ->where('email', $user->email)
                ->whereIn('status', ['pending', 'under_review', 'approved', 'payment_pending'])
                ->exists();

            if ($existingApplication) {
                return false;
            }
        }

        return true;
    }

    /**
     * Get the count of active mentors.
     */
    public function getActiveMentorsCount(): int
    {
        return $this->assignments()
            ->where('status', 'active')
            ->distinct('mentor_id')
            ->count('mentor_id');
    }

    /**
     * Get the count of active mentees.
     */
    public function getActiveMenteesCount(): int
    {
        return $this->assignments()
            ->where('status', 'active')
            ->distinct('mentee_id')
            ->count('mentee_id');
    }

    /**
     * Check if programme has available mentor slots.
     */
    public function hasMentorSlots(): bool
    {
        if ($this->max_mentors === 0) {
            return true;
        }

        return $this->getActiveMentorsCount() < $this->max_mentors;
    }

    /**
     * Check if programme has available mentee slots.
     */
    public function hasMenteeSlots(): bool
    {
        if ($this->max_mentees === 0) {
            return true;
        }

        return $this->getActiveMenteesCount() < $this->max_mentees;
    }

    /**
     * Activate the programme.
     */
    public function activate(): bool
    {
        return $this->update(['is_active' => true]);
    }

    /**
     * Deactivate the programme.
     */
    public function deactivate(): bool
    {
        return $this->update(['is_active' => false]);
    }

    /**
     * Update statistics.
     */
    public function updateStatistics(): void
    {
        $this->update([
            'applications_count' => $this->applications()->count(),
            'assignments_count' => $this->assignments()->count(),
            'completions_count' => $this->assignments()->where('status', 'completed')->count(),
        ]);
    }
}
