<?php

namespace App\Models;

use App\Models\Concerns\BelongsToCompany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Str;

class BiometricDevice extends Model
{
    use BelongsToCompany;

    public const PUNCH_MODE_LOGIN = 'login';

    public const PUNCH_MODE_LOGOUT = 'logout';

    public const PUNCH_MODE_BOTH = 'both';

    protected $table = 'biometric_devices';

    protected $fillable = [
        'company_id',
        'terminal_sn',
        'terminal_alias',
        'location_id',
        'api_username',
        'api_password_hash',
        'is_active',
        'punch_mode',
        'allowed_ips',
        'last_seen_at',
        'last_punch_at',
    ];

    protected $casts = [
        'is_active' => 'boolean',
        'allowed_ips' => 'array',
        'last_seen_at' => 'datetime',
        'last_punch_at' => 'datetime',
    ];

    protected $hidden = [
        'api_password_hash',
    ];

    /**
     * @return list<string>
     */
    public static function punchModes(): array
    {
        return [
            self::PUNCH_MODE_LOGIN,
            self::PUNCH_MODE_LOGOUT,
            self::PUNCH_MODE_BOTH,
        ];
    }

    public function punchModeLabel(): string
    {
        return match ($this->punch_mode) {
            self::PUNCH_MODE_LOGIN => 'Login only',
            self::PUNCH_MODE_LOGOUT => 'Logout only',
            default => 'Both (login & logout)',
        };
    }

    public function location(): BelongsTo
    {
        return $this->belongsTo(Location::class);
    }

    public function punches(): HasMany
    {
        return $this->hasMany(AttendancePunch::class, 'biometric_device_id');
    }

    public static function generateApiUsername(Company $company): string
    {
        $short = Str::slug((string) ($company->short_name ?: $company->name), '_');
        $short = Str::limit($short !== '' ? $short : 'co', 20, '');

        return 'dev_'.$short.'_'.Str::lower(Str::random(8));
    }

    public static function generateApiPassword(): string
    {
        return Str::password(32);
    }

    /**
     * @param  list<string>|null  $allowedIps
     */
    public function allowsIp(?string $ip, ?array $allowedIps = null): bool
    {
        $list = $allowedIps ?? ($this->allowed_ips ?? []);
        if (! is_array($list) || count($list) === 0) {
            return true;
        }
        if ($ip === null || $ip === '') {
            return false;
        }

        return in_array($ip, $list, true);
    }
}
