<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

final class Voucher extends Model
{
    use HasFactory;

    protected $fillable = [
        'code',
        'item_id',
        'item_name',
        'count',
        'proctype',
        'octet',
        'expire_date',
        'mask',
        'is_used',
        'used_by',
        'used_at',
        'redeemed_ip',
        'is_redeemed_by_ip',
        'usage_limit',
        'usage_count',
        'eligible_register_date',
    ];

    protected $casts = [
        'expire_date' => 'datetime',
        'is_used' => 'boolean',
        'used_at' => 'datetime',
        'is_redeemed_by_ip' => 'boolean',
        'eligible_register_date' => 'date',
    ];

    public function setEligibleRegisterDateAttribute($value): void
    {
        $this->attributes['eligible_register_date'] = empty($value) ? null : $value;
    }

    public static function normalizeCode(string $code): string
    {
        $normalized = preg_replace('/[^A-Z0-9]/', '', strtoupper($code));

        if (strlen($normalized) === 16) {
            return implode('-', str_split($normalized, 4));
        }

        return strtoupper(trim($code));
    }

    public function scopeByCode(Builder $query, string $code): Builder
    {
        return $query->where('code', self::normalizeCode($code));
    }

    public function scopeUnused(Builder $query): Builder
    {
        return $query->where('is_used', false);
    }

    public function scopeNotExpired(Builder $query): Builder
    {
        return $query->where(function (Builder $q): void {
            $q->whereNull('expire_date')
                ->orWhere('expire_date', '>=', now());
        });
    }

    public function scopeWithinUsageLimit(Builder $query): Builder
    {
        return $query->whereColumn('usage_count', '<', 'usage_limit');
    }

    public function isValid(): bool
    {
        if ($this->is_used) {
            return false;
        }

        if ($this->usage_count >= $this->usage_limit) {
            return false;
        }

        if ($this->expire_date && $this->expire_date < now()) {
            return false;
        }

        return true;
    }
}
