<?php

declare(strict_types=1);

namespace App\Models;

use App\Enums\EmploymentStatus;
use App\Enums\Gender;
use App\Models\Concerns\LogsHrActivity;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;

class Employee extends Model
{
    use HasFactory;
    use LogsHrActivity;
    use SoftDeletes;

    protected $fillable = [
        'employee_number',
        'full_name',
        'national_id',
        'gender',
        'birth_date',
        'phone',
        'address',
        'department_id',
        'position_id',
        'shift_id',
        'employment_status',
        'hire_date',
        'termination_date',
        'notes',
        'profile_photo_path',
    ];

    protected function casts(): array
    {
        return [
            'gender' => Gender::class,
            'birth_date' => 'date',
            'employment_status' => EmploymentStatus::class,
            'hire_date' => 'date',
            'termination_date' => 'date',
        ];
    }

    protected static function booted(): void
    {
        static::saving(function (Employee $employee): void {
            if (blank($employee->employee_number)) {
                $employee->employee_number = static::generateUniqueEmployeeNumber();
            }
        });
    }

    public static function generateUniqueEmployeeNumber(): string
    {
        $prefix = (string) config('hr.employee_number.prefix', 'EMP-');
        $padding = (int) config('hr.employee_number.padding', 5);

        $latestNumber = static::withTrashed()
            ->where('employee_number', 'like', $prefix.'%')
            ->pluck('employee_number')
            ->map(function (string $number) use ($prefix): ?int {
                if (! preg_match('/^'.preg_quote($prefix, '/').'(\d+)$/', $number, $matches)) {
                    return null;
                }

                return (int) $matches[1];
            })
            ->filter()
            ->max();

        $next = ($latestNumber ?? 0) + 1;

        return $prefix.str_pad((string) $next, $padding, '0', STR_PAD_LEFT);
    }

    public function department(): BelongsTo
    {
        return $this->belongsTo(Department::class);
    }

    public function position(): BelongsTo
    {
        return $this->belongsTo(Position::class);
    }

    public function shift(): BelongsTo
    {
        return $this->belongsTo(Shift::class);
    }

    public function vacations(): HasMany
    {
        return $this->hasMany(Vacation::class);
    }

    public function sickLeaves(): HasMany
    {
        return $this->hasMany(SickLeave::class);
    }

    public function unpaidLeaves(): HasMany
    {
        return $this->hasMany(UnpaidLeave::class);
    }

    public function disciplinaryReports(): HasMany
    {
        return $this->hasMany(DisciplinaryReport::class);
    }

    public function explanations(): HasMany
    {
        return $this->hasMany(Explanation::class);
    }

    public function bonuses(): HasMany
    {
        return $this->hasMany(Bonus::class);
    }

    public function gifts(): HasMany
    {
        return $this->hasMany(Gift::class);
    }

    public function documents(): HasMany
    {
        return $this->hasMany(EmployeeDocument::class);
    }
}
