<?php

namespace App\Models\SelfPaced;

use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Str;

/**
 * SelfPacedCertificate Model
 *
 * Issued certificate of completion for a passed exam.
 * Each certificate has a unique certificate_number and verification_code
 * used for the public Certificate_Verification page and QR code.
 *
 * @property int $id
 * @property int $user_id
 * @property int $course_id
 * @property int $enrollment_id
 * @property int $result_id
 * @property string $certificate_number
 * @property string $verification_code
 * @property \Illuminate\Support\Carbon $issue_date
 * @property bool $is_revoked
 * @property \Illuminate\Support\Carbon|null $revoked_at
 * @property int|null $revoked_by
 * @property string|null $revocation_reason
 * @property string|null $pdf_path
 * @property int $verification_count
 * @property \Illuminate\Support\Carbon|null $last_verified_at
 * @property int|null $generated_by
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 */
class SelfPacedCertificate extends Model
{
    protected $table = 'self_paced_certificates';

    protected $fillable = [
        'user_id',
        'course_id',
        'enrollment_id',
        'result_id',
        'certificate_number',
        'verification_code',
        'issue_date',
        'is_revoked',
        'revoked_at',
        'revoked_by',
        'revocation_reason',
        'pdf_path',
        'verification_count',
        'last_verified_at',
        'generated_by',
    ];

    protected $casts = [
        'issue_date'         => 'date',
        'is_revoked'         => 'boolean',
        'revoked_at'         => 'datetime',
        'verification_count' => 'integer',
        'last_verified_at'   => 'datetime',
        'created_at'         => 'datetime',
        'updated_at'         => 'datetime',
    ];

    protected $attributes = [
        'is_revoked'         => false,
        'verification_count' => 0,
    ];

    /**
     * Auto-generate certificate_number and verification_code on creation.
     */
    protected static function booted(): void
    {
        static::creating(function (self $cert) {
            if (empty($cert->certificate_number)) {
                $cert->certificate_number = static::generateCertificateNumber();
            }

            if (empty($cert->verification_code)) {
                $cert->verification_code = static::generateVerificationCode();
            }

            if (empty($cert->issue_date)) {
                $cert->issue_date = now()->toDateString();
            }
        });
    }

    // =========================================================================
    // 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 enrollment(): BelongsTo
    {
        return $this->belongsTo(Enrollment::class, 'enrollment_id');
    }

    public function result(): BelongsTo
    {
        return $this->belongsTo(ExamResult::class, 'result_id');
    }

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

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

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

    public function scopeValid($query)
    {
        return $query->where('is_revoked', false);
    }

    public function scopeRevoked($query)
    {
        return $query->where('is_revoked', true);
    }

    public function scopeForUser($query, int $userId)
    {
        return $query->where('user_id', $userId);
    }

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

    public function isValid(): bool
    {
        return !$this->is_revoked;
    }

    public function isRevoked(): bool
    {
        return $this->is_revoked;
    }

    /**
     * Revoke this certificate.
     */
    public function revoke(int $revokerId, string $reason): bool
    {
        return $this->update([
            'is_revoked'         => true,
            'revoked_at'         => now(),
            'revoked_by'         => $revokerId,
            'revocation_reason'  => $reason,
        ]);
    }

    /**
     * Record a public verification hit.
     */
    public function recordVerification(): void
    {
        $this->increment('verification_count');
        $this->update(['last_verified_at' => now()]);
    }

    public function hasPdf(): bool
    {
        return !empty($this->pdf_path);
    }

    public function getFormattedIssueDate(): string
    {
        return $this->issue_date->format('F j, Y');
    }

    public function getStatusText(): string
    {
        return $this->is_revoked ? 'Revoked' : 'Valid';
    }

    public function getStatusBadgeColor(): string
    {
        return $this->is_revoked ? 'red' : 'green';
    }

    // =========================================================================
    // STATIC GENERATORS
    // =========================================================================

    /**
     * Generate a unique certificate number.
     * Format: SP-CERT-{YEAR}-{8 random uppercase chars}
     */
    public static function generateCertificateNumber(): string
    {
        $year = now()->format('Y');
        $random = strtoupper(Str::random(8));

        return "SP-CERT-{$year}-{$random}";
    }

    /**
     * Generate a unique verification code (16 uppercase alphanumeric chars).
     * Property 7: Certificate verification code uniqueness.
     */
    public static function generateVerificationCode(): string
    {
        return strtoupper(Str::random(16));
    }
}
