<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Str;

/**
 * TrainingCertificate Model
 *
 * Represents a certificate issued for completed training.
 * Contains certificate details, verification information, and file paths.
 *
 * @property int $id
 * @property int $user_id
 * @property int $training_package_id
 * @property int|null $registration_id
 * @property string $certificate_number
 * @property string|null $title
 * @property string|null $description
 * @property string|null $skills_acquired
 * @property \Illuminate\Support\Carbon $issue_date
 * @property \Illuminate\Support\Carbon|null $expiry_date
 * @property bool $is_valid
 * @property string $format_type
 * @property string $template_used
 * @property string|null $certificate_path
 * @property string|null $pdf_path
 * @property string|null $thumbnail_path
 * @property string|null $trainer_signature_path
 * @property string|null $trainer_name
 * @property string|null $trainer_title
 * @property string|null $organization_seal_path
 * @property string|null $organization_name
 * @property string|null $organization_logo_path
 * @property string $verification_code
 * @property string|null $verification_url
 * @property int $verification_count
 * @property \Illuminate\Support\Carbon|null $last_verified_at
 * @property int|null $generated_by
 * @property bool $is_revoked
 * @property \Illuminate\Support\Carbon|null $revoked_at
 * @property int|null $revoked_by
 * @property string|null $revocation_reason
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 */
class TrainingCertificate extends Model
{
    use HasFactory;

    /**
     * The table associated with the model.
     *
     * @var string
     */
    protected $table = 'training_certificates';

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'user_id',
        'training_package_id',
        'registration_id',
        'certificate_number',
        'title',
        'description',
        'skills_acquired',
        'issue_date',
        'expiry_date',
        'is_valid',
        'format_type',
        'template_used',
        'certificate_path',
        'pdf_path',
        'thumbnail_path',
        'trainer_signature_path',
        'trainer_name',
        'trainer_title',
        'organization_seal_path',
        'organization_name',
        'organization_logo_path',
        'verification_code',
        'verification_url',
        'verification_count',
        'last_verified_at',
        'generated_by',
        'is_revoked',
        'revoked_at',
        'revoked_by',
        'revocation_reason',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'issue_date' => 'date',
        'expiry_date' => 'date',
        'is_valid' => 'boolean',
        'verification_count' => 'integer',
        'last_verified_at' => 'datetime',
        'is_revoked' => 'boolean',
        'revoked_at' => 'datetime',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
    ];

    /**
     * The model's default values for attributes.
     *
     * @var array
     */
    protected $attributes = [
        'format_type' => 'portrait',
        'template_used' => 'default',
        'is_valid' => true,
        'verification_count' => 0,
        'is_revoked' => false,
    ];

    /**
     * The "booted" method of the model.
     */
    protected static function booted(): void
    {
        static::creating(function (self $certificate) {
            if (empty($certificate->certificate_number)) {
                $certificate->certificate_number = self::generateCertificateNumber();
            }
            
            if (empty($certificate->verification_code)) {
                $certificate->verification_code = self::generateVerificationCode();
            }
        });
    }

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

    /**
     * Get the user who owns this certificate.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    /**
     * Get the training package for this certificate.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function trainingPackage(): BelongsTo
    {
        return $this->belongsTo(TrainingPackage::class, 'training_package_id');
    }

    /**
     * Get the registration associated with this certificate.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function registration(): BelongsTo
    {
        return $this->belongsTo(TrainingRegistration::class, 'registration_id');
    }

    /**
     * Get the user who generated this certificate.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function generator(): BelongsTo
    {
        return $this->belongsTo(User::class, 'generated_by');
    }

    /**
     * Get the user who revoked this certificate.
     *
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function revoker(): BelongsTo
    {
        return $this->belongsTo(User::class, 'revoked_by');
    }

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

    /**
     * Scope to get valid (non-revoked) certificates.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeValid($query)
    {
        return $query->where('is_valid', true)->where('is_revoked', false);
    }

    /**
     * Scope to get revoked certificates.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeRevoked($query)
    {
        return $query->where('is_revoked', true);
    }

    /**
     * Scope to get expired certificates.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeExpired($query)
    {
        return $query->whereNotNull('expiry_date')
            ->where('expiry_date', '<', now()->toDateString());
    }

    /**
     * Scope to get certificates by format.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param string $format
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeWithFormat($query, string $format)
    {
        return $query->where('format_type', $format);
    }

    /**
     * Scope to get certificates for a specific user.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param int $userId
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeForUser($query, int $userId)
    {
        return $query->where('user_id', $userId);
    }

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

    /**
     * Check if certificate is valid.
     *
     * @return bool
     */
    public function isValid(): bool
    {
        if ($this->is_revoked || !$this->is_valid) {
            return false;
        }
        
        if ($this->expiry_date && $this->expiry_date->isPast()) {
            return false;
        }
        
        return true;
    }

    /**
     * Check if certificate is expired.
     *
     * @return bool
     */
    public function isExpired(): bool
    {
        return $this->expiry_date && $this->expiry_date->isPast();
    }

    /**
     * Check if certificate is revoked.
     *
     * @return bool
     */
    public function isRevoked(): bool
    {
        return $this->is_revoked;
    }

    /**
     * Generate a unique certificate number.
     *
     * @return string
     */
    public static function generateCertificateNumber(): string
    {
        $prefix = 'CERT';
        $year = now()->format('Y');
        $random = strtoupper(Str::random(8));
        
        return "{$prefix}-{$year}-{$random}";
    }

    /**
     * Generate a unique verification code.
     *
     * @return string
     */
    public static function generateVerificationCode(): string
    {
        return strtoupper(Str::random(16));
    }

    /**
     * Get the verification URL.
     *
     * @return string
     */
    public function getVerificationUrlAttribute(): string
    {
        if (!empty($this->attributes['verification_url'])) {
            return $this->attributes['verification_url'];
        }
        
        return route('public.certificates.verify', $this->verification_code);
    }

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

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

    /**
     * Restore a revoked certificate.
     *
     * @return bool
     */
    public function restore(): bool
    {
        return $this->update([
            'is_revoked' => false,
            'is_valid' => true,
            'revoked_at' => null,
            'revoked_by' => null,
            'revocation_reason' => null,
        ]);
    }

    /**
     * Get formatted issue date.
     *
     * @return string
     */
    public function getFormattedIssueDate(): string
    {
        return $this->issue_date->format('F j, Y');
    }

    /**
     * Get formatted expiry date.
     *
     * @return string|null
     */
    public function getFormattedExpiryDate(): ?string
    {
        return $this->expiry_date?->format('F j, Y');
    }

    /**
     * Check if certificate has a PDF file.
     *
     * @return bool
     */
    public function hasPdf(): bool
    {
        return !empty($this->pdf_path);
    }

    /**
     * Check if certificate has an image file.
     *
     * @return bool
     */
    public function hasImage(): bool
    {
        return !empty($this->certificate_path);
    }

    /**
     * Get the status badge color for UI.
     *
     * @return string
     */
    public function getStatusBadgeColor(): string
    {
        if ($this->is_revoked) {
            return 'red';
        }
        
        if ($this->isExpired()) {
            return 'orange';
        }
        
        if ($this->isValid()) {
            return 'green';
        }
        
        return 'gray';
    }

    /**
     * Get the status text for display.
     *
     * @return string
     */
    public function getStatusText(): string
    {
        if ($this->is_revoked) {
            return 'Revoked';
        }
        
        if ($this->isExpired()) {
            return 'Expired';
        }
        
        if ($this->isValid()) {
            return 'Valid';
        }
        
        return 'Invalid';
    }
}
