<?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\HasOne;

/**
 * ExamAttempt Model
 *
 * A single sitting of an Exam by a Trainee. Stores the ordered question list,
 * saved answers JSON, timer boundaries, and submission status.
 *
 * @property int $id
 * @property int $enrollment_id
 * @property int $user_id
 * @property int $course_id
 * @property \Illuminate\Support\Carbon|null $started_at
 * @property \Illuminate\Support\Carbon|null $submitted_at
 * @property \Illuminate\Support\Carbon|null $expires_at
 * @property string $status
 * @property array|null $answers
 * @property array|null $question_ids
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 */
class ExamAttempt extends Model
{
    protected $table = 'self_paced_exam_attempts';

    protected $fillable = [
        'enrollment_id',
        'user_id',
        'course_id',
        'started_at',
        'submitted_at',
        'expires_at',
        'status',
        'answers',
        'question_ids',
        'topic_groups',
    ];

    protected $casts = [
        'started_at'   => 'datetime',
        'submitted_at' => 'datetime',
        'expires_at'   => 'datetime',
        'answers'      => 'array',
        'question_ids' => 'array',
        'topic_groups' => 'array',
        'created_at'   => 'datetime',
        'updated_at'   => 'datetime',
    ];

    protected $attributes = [
        'status' => 'in_progress',
    ];

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

    public function enrollment(): BelongsTo
    {
        return $this->belongsTo(Enrollment::class, 'enrollment_id');
    }

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

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

    public function result(): HasOne
    {
        return $this->hasOne(ExamResult::class, 'attempt_id');
    }

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

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

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

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

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

    /**
     * Compute remaining seconds for this attempt.
     * Property 4: Exam timer integrity.
     *
     * Returns the number of seconds left before the attempt expires.
     * Returns 0 (or negative clamped to 0) when the timer has run out.
     */
    public function getRemainingSeconds(): int
    {
        if ($this->expires_at === null || $this->started_at === null) {
            return 0;
        }

        $remaining = (int) now()->diffInSeconds($this->expires_at, false);

        return max(0, $remaining);
    }

    /**
     * Check whether the attempt has expired server-side.
     */
    public function isExpired(): bool
    {
        if ($this->expires_at === null) {
            return false;
        }

        return now()->greaterThanOrEqualTo($this->expires_at);
    }

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

    public function isSubmitted(): bool
    {
        return in_array($this->status, ['submitted', 'timed_out'], true);
    }

    /**
     * Save (or overwrite) the answer for a single question — idempotent.
     * For multi-answer questions, $selectedOption is a sorted comma-separated string like "A,C".
     * Property 9: Exam answer persistence.
     */
    public function saveAnswer(int $questionId, string $selectedOption): void
    {
        $answers = $this->answers ?? [];
        $answers[(string) $questionId] = strtoupper($selectedOption);
        $this->answers = $answers;
        $this->save();
    }

    /**
     * Get the answer saved for a specific question, or null if not answered.
     * Returns a string — either a single letter 'A' or comma-separated 'A,C'.
     */
    public function getAnswerFor(int $questionId): ?string
    {
        return ($this->answers ?? [])[(string) $questionId] ?? null;
    }

    /**
     * Return the index (0-based) of the last answered question in question_ids.
     */
    public function getLastAnsweredIndex(): int
    {
        $ids = $this->question_ids ?? [];
        $answers = $this->answers ?? [];

        $lastIndex = -1;
        foreach ($ids as $index => $qid) {
            if (isset($answers[(string) $qid])) {
                $lastIndex = $index;
            }
        }

        return $lastIndex;
    }
}
