<?php

namespace App\Models\Mentorship;

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

class Assignment extends Model
{
    use HasFactory, SoftDeletes;

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

    /**
     * The attributes that are mass assignable.
     */
    protected $fillable = [
        'programme_id',
        'mentor_id',
        'mentee_id',
        'mentor_application_id',
        'mentee_application_id',
        'matching_criteria',
        'goals',
        'notes',
        'start_date',
        'end_date',
        'preferred_meeting_time',
        'meeting_frequency',
        'status',
        'progress_percentage',
        'sessions_completed',
        'sessions_total',
        'milestones',
        'last_session_at',
        'next_session_at',
        'completed_at',
        'completion_notes',
        'certificate_eligible',
        'certificate_issued',
        'mentor_rating',
        'mentor_feedback',
        'mentee_rating',
        'mentee_feedback',
        'assigned_by',
        'assigned_at',
        'mentor_accepted_at',
        'mentee_accepted_at',
        'previous_assignment_id',
        'reassignment_reason',
    ];

    /**
     * The attributes that should be cast.
     */
    protected $casts = [
        'start_date' => 'date',
        'end_date' => 'date',
        'milestones' => 'array',
        'progress_percentage' => 'integer',
        'sessions_completed' => 'integer',
        'sessions_total' => 'integer',
        'certificate_eligible' => 'boolean',
        'certificate_issued' => 'boolean',
        'mentor_rating' => 'integer',
        'mentee_rating' => 'integer',
        'assigned_at' => 'datetime',
        'mentor_accepted_at' => 'datetime',
        'mentee_accepted_at' => 'datetime',
        'last_session_at' => 'datetime',
        'next_session_at' => 'datetime',
        'completed_at' => 'datetime',
    ];

    /*
    |--------------------------------------------------------------------------
    | Status Constants
    |--------------------------------------------------------------------------
    */

    const STATUS_PENDING_ACCEPTANCE = 'pending_acceptance';
    const STATUS_ACTIVE = 'active';
    const STATUS_ON_HOLD = 'on_hold';
    const STATUS_COMPLETED = 'completed';
    const STATUS_CANCELLED = 'cancelled';
    const STATUS_REASSIGNED = 'reassigned';

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

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

    /**
     * Get the mentor (user).
     */
    public function mentor()
    {
        return $this->belongsTo(\App\Models\User::class, 'mentor_id');
    }

    /**
     * Get the mentee (user).
     */
    public function mentee()
    {
        return $this->belongsTo(\App\Models\User::class, 'mentee_id');
    }

    /**
     * Get the mentor's application.
     */
    public function mentorApplication()
    {
        return $this->belongsTo(Application::class, 'mentor_application_id');
    }

    /**
     * Get the mentee's application.
     */
    public function menteeApplication()
    {
        return $this->belongsTo(Application::class, 'mentee_application_id');
    }

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

    /**
     * Get the certificate for this assignment.
     */
    public function certificate()
    {
        return $this->hasOne(Certificate::class, 'assignment_id');
    }

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

    /**
     * Get the previous assignment (if this is a reassignment).
     */
    public function previousAssignment()
    {
        return $this->belongsTo(self::class, 'previous_assignment_id');
    }

    /**
     * Get subsequent assignments (reassignments from this one).
     */
    public function subsequentAssignments()
    {
        return $this->hasMany(self::class, 'previous_assignment_id');
    }

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

    /**
     * Scope to get pending assignments.
     */
    public function scopePendingAcceptance($query)
    {
        return $query->where('status', self::STATUS_PENDING_ACCEPTANCE);
    }

    /**
     * Scope to get active assignments.
     */
    public function scopeActive($query)
    {
        return $query->where('status', self::STATUS_ACTIVE);
    }

    /**
     * Scope to get completed assignments.
     */
    public function scopeCompleted($query)
    {
        return $query->where('status', self::STATUS_COMPLETED);
    }

    /**
     * Scope to get assignments for a specific programme.
     */
    public function scopeForProgramme($query, $programmeId)
    {
        return $query->where('programme_id', $programmeId);
    }

    /**
     * Scope to get assignments for a specific mentor.
     */
    public function scopeForMentor($query, $mentorId)
    {
        return $query->where('mentor_id', $mentorId);
    }

    /**
     * Scope to get assignments for a specific mentee.
     */
    public function scopeForMentee($query, $menteeId)
    {
        return $query->where('mentee_id', $menteeId);
    }

    /**
     * Scope to get assignments eligible for certificates.
     */
    public function scopeCertificateEligible($query)
    {
        return $query->where('certificate_eligible', true)
            ->where('certificate_issued', false);
    }

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

    /**
     * Get the status label.
     */
    public function getStatusLabelAttribute(): string
    {
        return match($this->status) {
            self::STATUS_PENDING_ACCEPTANCE => 'Pending Acceptance',
            self::STATUS_ACTIVE => 'Active',
            self::STATUS_ON_HOLD => 'On Hold',
            self::STATUS_COMPLETED => 'Completed',
            self::STATUS_CANCELLED => 'Cancelled',
            self::STATUS_REASSIGNED => 'Reassigned',
            default => ucfirst($this->status),
        };
    }

    /**
     * Get the status color for badges.
     */
    public function getStatusColorAttribute(): string
    {
        return match($this->status) {
            self::STATUS_PENDING_ACCEPTANCE => 'yellow',
            self::STATUS_ACTIVE => 'green',
            self::STATUS_ON_HOLD => 'orange',
            self::STATUS_COMPLETED => 'blue',
            self::STATUS_CANCELLED => 'red',
            self::STATUS_REASSIGNED => 'purple',
            default => 'gray',
        };
    }

    /**
     * Get the duration in days.
     */
    public function getDurationDaysAttribute(): int
    {
        if (!$this->start_date || !$this->end_date) {
            return 0;
        }

        return $this->start_date->diffInDays($this->end_date);
    }

    /**
     * Get the progress as a percentage.
     */
    public function getProgressAttribute(): int
    {
        if ($this->progress_percentage > 0) {
            return min(100, $this->progress_percentage);
        }

        if ($this->sessions_total > 0) {
            return min(100, (int) (($this->sessions_completed / $this->sessions_total) * 100));
        }

        return 0;
    }

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

    /**
     * Check if the assignment is pending.
     */
    public function isPending(): bool
    {
        return $this->status === self::STATUS_PENDING_ACCEPTANCE;
    }

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

    /**
     * Check if the assignment is completed.
     */
    public function isCompleted(): bool
    {
        return $this->status === self::STATUS_COMPLETED;
    }

    /**
     * Check if mentor has accepted.
     */
    public function mentorHasAccepted(): bool
    {
        return !is_null($this->mentor_accepted_at);
    }

    /**
     * Check if mentee has accepted.
     */
    public function menteeHasAccepted(): bool
    {
        return !is_null($this->mentee_accepted_at);
    }

    /**
     * Check if both parties have accepted.
     */
    public function isFullyAccepted(): bool
    {
        return $this->mentorHasAccepted() && $this->menteeHasAccepted();
    }

    /**
     * Accept as mentor.
     */
    public function acceptAsMentor(): bool
    {
        $updated = $this->update(['mentor_accepted_at' => now()]);

        if ($updated && $this->menteeHasAccepted()) {
            $this->activate();
        }

        return $updated;
    }

    /**
     * Accept as mentee.
     */
    public function acceptAsMentee(): bool
    {
        $updated = $this->update(['mentee_accepted_at' => now()]);

        if ($updated && $this->mentorHasAccepted()) {
            $this->activate();
        }

        return $updated;
    }

    /**
     * Activate the assignment.
     */
    public function activate(): bool
    {
        if (!$this->isFullyAccepted()) {
            return false;
        }

        return $this->update(['status' => self::STATUS_ACTIVE]);
    }

    /**
     * Put assignment on hold.
     */
    public function putOnHold(string $reason): bool
    {
        return $this->update([
            'status' => self::STATUS_ON_HOLD,
            'notes' => $this->notes . "\n\nOn Hold: " . $reason,
        ]);
    }

    /**
     * Complete the assignment.
     */
    public function complete(string $notes = null): bool
    {
        $data = [
            'status' => self::STATUS_COMPLETED,
            'completed_at' => now(),
            'progress_percentage' => 100,
            'certificate_eligible' => true,
        ];

        if ($notes) {
            $data['completion_notes'] = $notes;
        }

        return $this->update($data);
    }

    /**
     * Cancel the assignment.
     */
    public function cancel(string $reason): bool
    {
        return $this->update([
            'status' => self::STATUS_CANCELLED,
            'completion_notes' => $reason,
        ]);
    }

    /**
     * Update progress.
     */
    public function updateProgress(): void
    {
        $completedSessions = $this->sessions()->where('status', 'completed')->count();
        $totalSessions = $this->sessions_total ?: $this->programme->sessions_count ?: 0;

        $this->update([
            'sessions_completed' => $completedSessions,
            'progress_percentage' => $totalSessions > 0 ? (int) (($completedSessions / $totalSessions) * 100) : 0,
            'last_session_at' => $this->sessions()->where('status', 'completed')->latest('start_time')->value('start_time'),
            'next_session_at' => $this->sessions()->scheduled()->orderBy('start_time')->value('start_time'),
        ]);
    }

    /**
     * Get upcoming sessions.
     */
    public function upcomingSessions()
    {
        return $this->sessions()
            ->where('start_time', '>', now())
            ->whereIn('status', ['scheduled', 'confirmed'])
            ->orderBy('start_time');
    }

    /**
     * Get completed sessions.
     */
    public function completedSessions()
    {
        return $this->sessions()
            ->where('status', 'completed')
            ->orderBy('start_time', 'desc');
    }
}
