<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class EmailVerificationOtp extends Model
{
    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected $fillable = [
        'email',
        'otp_code',
        'expires_at',
        'is_used',
        'used_at',
        'ip_address',
        'user_agent',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'expires_at' => 'datetime',
            'is_used' => 'boolean',
            'used_at' => 'datetime',
        ];
    }

    /**
     * Generate a random 6-digit OTP code.
     */
    public static function generateOtp(): string
    {
        return str_pad((string) random_int(100000, 999999), 6, '0', STR_PAD_LEFT);
    }

    /**
     * Create a new OTP for email verification.
     */
    public static function createForEmail(string $email, ?string $ipAddress = null, ?string $userAgent = null): self
    {
        // Invalidate all previous unused OTPs for this email
        static::where('email', $email)
            ->where('is_used', false)
            ->where('expires_at', '>', now())
            ->update(['is_used' => true, 'used_at' => now()]);

        // Create new OTP (expires in 10 minutes)
        return static::create([
            'email' => $email,
            'otp_code' => static::generateOtp(),
            'expires_at' => now()->addMinutes(10),
            'ip_address' => $ipAddress,
            'user_agent' => $userAgent,
        ]);
    }

    /**
     * Verify OTP code.
     */
    public static function verify(string $email, string $otpCode): bool
    {
        $otp = static::where('email', $email)
            ->where('otp_code', $otpCode)
            ->where('is_used', false)
            ->where('expires_at', '>', now())
            ->first();

        if (! $otp) {
            return false;
        }

        // Mark as used
        $otp->update([
            'is_used' => true,
            'used_at' => now(),
        ]);

        return true;
    }

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

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

    /**
     * Clean up expired OTPs (can be called via scheduler).
     */
    public static function cleanupExpired(): int
    {
        return static::where('expires_at', '<', now())
            ->orWhere(function ($query) {
                $query->where('is_used', true)
                    ->where('used_at', '<', now()->subDays(7));
            })
            ->delete();
    }
}
