<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Hash;

class TwoFactorCode extends Model
{
    use HasFactory;

    protected $fillable = [
        'authenticatable_id',
        'authenticatable_type',
        'code_hash',
        'expires_at',
        'attempts',
        'used',
        'verified_at',
    ];

    protected function casts(): array
    {
        return [
            'expires_at' => 'datetime',
            'verified_at' => 'datetime',
            'used' => 'boolean',
            'attempts' => 'integer',
        ];
    }

    /**
     * Get the parent authenticatable model (User or PortalUser).
     */
    public function authenticatable()
    {
        return $this->morphTo();
    }

    /**
     * Check if the code has expired.
     */
    public function isExpired(): bool
    {
        return $this->expires_at->isPast();
    }

    /**
     * Check if the code has been used.
     */
    public function isUsed(): bool
    {
        return $this->used;
    }

    /**
     * Check if the code is still valid (not expired and not used).
     */
    public function isValid(): bool
    {
        return ! $this->isExpired() && ! $this->isUsed();
    }

    /**
     * Check if the code has exceeded maximum attempts.
     */
    public function hasExceededAttempts(): bool
    {
        return $this->attempts >= 5;
    }

    /**
     * Increment the attempts counter.
     */
    public function incrementAttempts(): void
    {
        $this->increment('attempts');
    }

    /**
     * Mark the code as used.
     */
    public function markAsUsed(): void
    {
        $this->used = true;
        $this->verified_at = now();
        $this->save();
    }

    /**
     * Verify if the provided code matches this record.
     */
    public function verify(string $code): bool
    {
        return Hash::check($code, $this->code_hash);
    }

    /**
     * Scope to get only valid codes.
     */
    public function scopeValid($query)
    {
        return $query->where('used', false)
            ->where('expires_at', '>', now());
    }

    /**
     * Scope to get codes for a specific authenticatable.
     */
    public function scopeForAuthenticatable($query, $authenticatable)
    {
        return $query->where('authenticatable_type', get_class($authenticatable))
            ->where('authenticatable_id', $authenticatable->id);
    }
}
