<?php

namespace App\Domain\HR\Services;

use App\Domain\HR\Enums\EmployeeStatus;
use App\Domain\HR\Models\Employee;
use App\Domain\Identity\Models\User;
use App\Domain\Organization\Models\Branch;
use App\Support\Sequences\SequenceGenerator;
use Illuminate\Support\Facades\DB;

class EmployeeService
{
    public function __construct(private readonly SequenceGenerator $sequences) {}

    /**
     * @param  array<string, mixed>  $attributes
     */
    public function create(array $attributes, ?User $actor = null): Employee
    {
        return DB::transaction(function () use ($attributes, $actor) {
            // Defaults are declared here as well as in the schema, so the returned
            // model reflects what was stored without a round trip.
            $attributes['status'] ??= EmployeeStatus::Active->value;
            $attributes['employment_type'] ??= 'full_time';

            $attributes['employee_code'] ??= $this->generateCode(
                (int) $attributes['company_id'],
                $attributes['branch_id'] ?? null,
            );

            $attributes['created_by'] = $actor?->getKey();
            $attributes['updated_by'] = $actor?->getKey();

            return Employee::create($attributes);
        });
    }

    /**
     * @param  array<string, mixed>  $attributes
     */
    public function update(Employee $employee, array $attributes, ?User $actor = null): Employee
    {
        return DB::transaction(function () use ($employee, $attributes, $actor) {
            // The code identifies the employee in payroll history; it is not editable.
            unset($attributes['employee_code'], $attributes['company_id']);

            $attributes['updated_by'] = $actor?->getKey();
            $employee->fill($attributes)->save();

            return $employee;
        });
    }

    /**
     * Employee codes are per company and prefixed with the branch, so a record
     * reads as EMP-DHK-000012.
     */
    public function generateCode(int $companyId, ?int $branchId): string
    {
        $branchCode = $branchId !== null
            ? (Branch::whereKey($branchId)->value('code') ?? 'HO')
            : 'HO';

        return $this->sequences->next('employee', 'EMP', [$branchCode], 6);
    }
}
