<?php

namespace App\Models\SelfPaced;

use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;

/**
 * Enrollment Model
 *
 * Tracks a Trainee's paid registration for a Course including payment
 * details and lifecycle status.
 *
 * @property int $id
 * @property int $user_id
 * @property int $course_id
 * @property string $status
 * @property string|null $payment_reference
 * @property string $payment_method
 * @property float $amount_paid
 * @property \Illuminate\Support\Carbon|null $payment_date
 * @property \Illuminate\Support\Carbon|null $enrolled_at
 * @property \Illuminate\Support\Carbon|null $completed_at
 * @property int|null $created_by
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 */
class Enrollment extends Model
{
    protected $table = 'self_paced_enrollments';

    protected $fillable = [
        'user_id',
        'course_id',
        'status',
        'payment_reference',
        'payment_method',
        'amount_paid',
        'payment_date',
        'enrolled_at',
        'completed_at',
        'created_by',
        // New fields
        'currency',
        'registration_fee_paid',
        'application_fee_paid',
        'certificate_fee_paid',
        'exam_unlocked_at',
        'exam_exhausted',
        'resit_attempt_count',
        'content_access_expires_at',
    ];

    protected $casts = [
        'amount_paid'                => 'decimal:2',
        'payment_date'               => 'datetime',
        'enrolled_at'                => 'datetime',
        'completed_at'               => 'datetime',
        'created_at'                 => 'datetime',
        'updated_at'                 => 'datetime',
        // New field casts
        'registration_fee_paid'      => 'decimal:2',
        'application_fee_paid'       => 'decimal:2',
        'certificate_fee_paid'       => 'boolean',
        'exam_unlocked_at'           => 'datetime',
        'exam_exhausted'             => 'boolean',
        'resit_attempt_count'        => 'integer',
        'content_access_expires_at'  => 'datetime',
    ];

    protected $attributes = [
        'status'         => 'pending_payment',
        'payment_method' => 'paystack',
        'amount_paid'    => 0.00,
    ];

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

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    public function course(): BelongsTo
    {
        return $this->belongsTo(Course::class, 'course_id');
    }

    public function creator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'created_by');
    }

    public function examAttempts(): HasMany
    {
        return $this->hasMany(ExamAttempt::class, 'enrollment_id');
    }

    public function examResults(): HasMany
    {
        return $this->hasMany(ExamResult::class, 'enrollment_id');
    }

    public function learningProgress(): HasMany
    {
        return $this->hasMany(LearningProgress::class, 'enrollment_id');
    }

    public function topicTimers(): HasMany
    {
        return $this->hasMany(TopicTimer::class, 'enrollment_id');
    }

    public function certificate(): HasOne
    {
        return $this->hasOne(SelfPacedCertificate::class, 'enrollment_id');
    }

    public function certificatePayment(): HasOne
    {
        return $this->hasOne(CertificatePayment::class, 'enrollment_id');
    }

    public function resitPayments(): HasMany
    {
        return $this->hasMany(ResitPayment::class, 'enrollment_id');
    }

    public function paymentProofs(): HasMany
    {
        return $this->hasMany(PaymentProof::class, 'enrollment_id');
    }

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

    public function scopeActive($query)
    {
        return $query->where('status', 'active');
    }

    public function scopeCompleted($query)
    {
        return $query->where('status', 'completed');
    }

    public function scopePendingPayment($query)
    {
        return $query->where('status', 'pending_payment');
    }

    public function scopePaymentFailed($query)
    {
        return $query->where('status', 'payment_failed');
    }

    public function scopeAccessible($query)
    {
        return $query->whereIn('status', ['active', 'completed']);
    }

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

    /**
     * Returns true only when the enrollment grants Learner Portal access.
     * Property 2: Payment-gated access invariant.
     */
    public function canAccess(): bool
    {
        return in_array($this->status, ['active', 'completed'], true);
    }

    public function isDeregistered(): bool
    {
        return $this->status === 'deregistered';
    }

    public function isPendingVerification(): bool
    {
        return $this->status === 'pending_verification';
    }

    public function isExamUnlocked(): bool
    {
        return $this->exam_unlocked_at !== null;
    }

    public function isAccessExpired(): bool
    {
        if ($this->content_access_expires_at === null) {
            return false;
        }
        return now()->greaterThan($this->content_access_expires_at);
    }

    public function canDownloadCertificate(): bool
    {
        // Must have a passing result
        if (!$this->getPassedResult()) {
            return false;
        }

        // Must be in self-download mode
        if (!$this->course->isSelfDownloadCertificate()) {
            return false;
        }

        // Must have paid certificate fee (or fee is 0)
        return ((float)$this->course->certificate_fee === 0.0) || $this->certificate_fee_paid;
    }

    public function getRemainingAttempts(): int
    {
        $used = $this->examAttempts()
            ->whereIn('status', ['submitted', 'timed_out'])
            ->count();

        return max(0, $this->course->max_exam_attempts - $used);
    }

    public function isExamExhausted(): bool
    {
        return $this->exam_exhausted === true;
    }

    /**
     * Verify that registration_fee_paid + application_fee_paid = amount_paid (approximately)
     *
     * @return bool
     */
    public function verifyFeeSumIntegrity(): bool
    {
        $sum = ((float)$this->registration_fee_paid + (float)$this->application_fee_paid);
        $amount = (float)$this->amount_paid;
        // Allow 0.01 tolerance for floating point precision
        return abs($sum - $amount) < 0.01;
    }

    public function isActive(): bool
    {
        return $this->status === 'active';
    }

    public function isCompleted(): bool
    {
        return $this->status === 'completed';
    }

    public function isPendingPayment(): bool
    {
        return $this->status === 'pending_payment';
    }

    public function isPaymentFailed(): bool
    {
        return $this->status === 'payment_failed';
    }

    public function isCancelled(): bool
    {
        return $this->status === 'cancelled';
    }

    /**
     * Count how many exam attempts remain for this enrollment.
     */
    public function getRemainingAttempts(): int
    {
        $used = $this->examAttempts()
            ->whereIn('status', ['submitted', 'timed_out'])
            ->count();

        return max(0, $this->course->exam_attempts_allowed - $used);
    }

    /**
     * Check if the trainee can retake the exam.
     */
    public function canRetakeExam(): bool
    {
        return $this->getRemainingAttempts() > 0;
    }

    /**
     * Get the active (in-progress) exam attempt, if any.
     */
    public function getActiveAttempt(): ?ExamAttempt
    {
        return $this->examAttempts()
            ->where('status', 'in_progress')
            ->latest()
            ->first();
    }

    /**
     * Get the latest passed exam result, if any.
     */
    public function getPassedResult(): ?ExamResult
    {
        return $this->examResults()->where('passed', true)->latest()->first();
    }

    /**
     * Calculate overall course progress percentage (based on subtopics read).
     */
    public function getProgressPercentage(): float
    {
        $total = CourseSubTopic::whereHas('topic', fn ($q) => $q->where('course_id', $this->course_id))
            ->where('is_published', true)
            ->count();

        if ($total === 0) {
            return 0.0;
        }

        $completed = $this->learningProgress()->count();

        return round(min(100, ($completed / $total) * 100), 2);
    }
}
