<?php

namespace App\Models\Mentorship;

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

class Certificate extends Model
{
    use HasFactory, SoftDeletes;

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

    /**
     * The attributes that are mass assignable.
     */
    protected $fillable = [
        'assignment_id',
        'programme_id',
        'user_id',
        'certificate_number',
        'verification_code',
        'recipient_name',
        'programme_name',
        'description',
        'skills_acquired',
        'orientation',
        'template',
        'custom_fields',
        'organization_name',
        'organization_address',
        'organization_seal',
        'organization_logo',
        'signatory_name',
        'signatory_title',
        'signatory_signature',
        'mentor_name',
        'mentor_signature',
        'completion_date',
        'issue_date',
        'expiry_date',
        'file_path',
        'file_name',
        'file_type',
        'file_size',
        'download_count',
        'first_downloaded_at',
        'last_downloaded_at',
        'download_history',
        'generated_by',
        'generated_at',
        'generation_ip',
        'status',
        'revoked_at',
        'revocation_reason',
        'revoked_by',
        'verification_count',
        'last_verified_at',
    ];

    /**
     * The attributes that should be cast.
     */
    protected $casts = [
        'skills_acquired' => 'array',
        'custom_fields' => 'array',
        'download_history' => 'array',
        'completion_date' => 'date',
        'issue_date' => 'date',
        'expiry_date' => 'date',
        'file_size' => 'integer',
        'download_count' => 'integer',
        'verification_count' => 'integer',
        'generated_at' => 'datetime',
        'first_downloaded_at' => 'datetime',
        'last_downloaded_at' => 'datetime',
        'last_verified_at' => 'datetime',
        'revoked_at' => 'datetime',
    ];

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

    const STATUS_ACTIVE = 'active';
    const STATUS_REVOKED = 'revoked';
    const STATUS_EXPIRED = 'expired';

    /*
    |--------------------------------------------------------------------------
    | Orientation Constants
    |--------------------------------------------------------------------------
    */

    const ORIENTATION_PORTRAIT = 'portrait';
    const ORIENTATION_LANDSCAPE = 'landscape';

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

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

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

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

    /**
     * Get the user who generated this certificate.
     */
    public function generator()
    {
        return $this->belongsTo(\App\Models\User::class, 'generated_by');
    }

    /**
     * Get the user who revoked this certificate.
     */
    public function revoker()
    {
        return $this->belongsTo(\App\Models\User::class, 'revoked_by');
    }

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

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

    /**
     * Scope to get revoked certificates.
     */
    public function scopeRevoked($query)
    {
        return $query->where('status', self::STATUS_REVOKED);
    }

    /**
     * Scope to get expired certificates.
     */
    public function scopeExpired($query)
    {
        return $query->where('status', self::STATUS_EXPIRED)
            ->orWhere('expiry_date', '<', now());
    }

    /**
     * Scope to get certificates for a specific user.
     */
    public function scopeForUser($query, $userId)
    {
        return $query->where('user_id', $userId);
    }

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

    /**
     * Scope to find by verification code.
     */
    public function scopeByVerificationCode($query, $code)
    {
        return $query->where('verification_code', $code);
    }

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

    /**
     * Get the status label.
     */
    public function getStatusLabelAttribute(): string
    {
        return match($this->status) {
            self::STATUS_ACTIVE => 'Active',
            self::STATUS_REVOKED => 'Revoked',
            self::STATUS_EXPIRED => 'Expired',
            default => ucfirst($this->status),
        };
    }

    /**
     * Get the status color for badges.
     */
    public function getStatusColorAttribute(): string
    {
        return match($this->status) {
            self::STATUS_ACTIVE => 'green',
            self::STATUS_REVOKED => 'red',
            self::STATUS_EXPIRED => 'gray',
            default => 'gray',
        };
    }

    /**
     * Get the orientation label.
     */
    public function getOrientationLabelAttribute(): string
    {
        return $this->orientation === self::ORIENTATION_LANDSCAPE ? 'Landscape (A4)' : 'Portrait (A4)';
    }

    /**
     * Check if certificate is valid.
     */
    public function getIsValidAttribute(): bool
    {
        if ($this->status !== self::STATUS_ACTIVE) {
            return false;
        }

        if ($this->expiry_date && $this->expiry_date->isPast()) {
            return false;
        }

        return true;
    }

    /**
     * Get the verification URL.
     */
    public function getVerificationUrlAttribute(): string
    {
        return route('mentorship.certificates.verify', $this->verification_code);
    }

    /**
     * Get the download URL.
     */
    public function getDownloadUrlAttribute(): string
    {
        return route('mentorship.certificates.download', $this->id);
    }

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

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

    /**
     * Check if the certificate is revoked.
     */
    public function isRevoked(): bool
    {
        return $this->status === self::STATUS_REVOKED;
    }

    /**
     * Check if the certificate is expired.
     */
    public function isExpired(): bool
    {
        if ($this->status === self::STATUS_EXPIRED) {
            return true;
        }

        return $this->expiry_date && $this->expiry_date->isPast();
    }

    /**
     * Check if certificate is valid for verification.
     */
    public function isValidForVerification(): bool
    {
        return $this->is_valid;
    }

    /**
     * Generate certificate number.
     */
    public static function generateCertificateNumber(): string
    {
        $prefix = 'CERT';
        $year = date('Y');
        $random = strtoupper(Str::random(6));
        $number = $prefix . '-' . $year . '-' . $random;

        // Ensure uniqueness
        while (self::where('certificate_number', $number)->exists()) {
            $random = strtoupper(Str::random(6));
            $number = $prefix . '-' . $year . '-' . $random;
        }

        return $number;
    }

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

    /**
     * Record a download.
     */
    public function recordDownload(string $ip = null): void
    {
        $downloadHistory = $this->download_history ?? [];
        $downloadHistory[] = [
            'downloaded_at' => now()->toIso8601String(),
            'ip' => $ip,
        ];

        $this->update([
            'download_count' => $this->download_count + 1,
            'last_downloaded_at' => now(),
            'first_downloaded_at' => $this->first_downloaded_at ?? now(),
            'download_history' => $downloadHistory,
        ]);
    }

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

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

    /**
     * Mark as expired.
     */
    public function markAsExpired(): bool
    {
        return $this->update(['status' => self::STATUS_EXPIRED]);
    }

    /**
     * Set file information.
     */
    public function setFileInfo(string $path, string $name, string $type, int $size): bool
    {
        return $this->update([
            'file_path' => $path,
            'file_name' => $name,
            'file_type' => $type,
            'file_size' => $size,
        ]);
    }

    /**
     * Verify by code.
     */
    public static function verifyByCode(string $code): ?self
    {
        $certificate = self::where('verification_code', $code)->first();

        if ($certificate) {
            $certificate->recordVerification();
        }

        return $certificate;
    }
}
