<?php

declare(strict_types=1);

namespace Kylin\Hr\Services;

use Kylin\Hr\Enums\EmployeeStatus;
use Kylin\Hr\Models\Employee;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Throwable;

class EmployeeService
{
    /**
     * 创建员工（入职登记）
     *
     * @param  array<string, mixed>  $data
     *
     * @throws Throwable
     */
    public function createEmployee(array $data): Employee
    {
        return DB::transaction(function () use ($data): Employee {
            $employee = Employee::create($data);

            Log::info('员工入职登记完成', [
                'employee_id' => $employee->id,
                'code' => $employee->code,
            ]);

            $this->audit('employee_created', $employee, ['code' => $employee->code]);

            return $employee;
        });
    }

    /**
     * 更新员工信息
     */
    public function updateEmployee(int $id, array $data): Employee
    {
        $employee = Employee::findOrFail($id);
        $oldValues = $employee->only(array_keys($data));
        $employee->update($data);

        $this->audit('employee_updated', $employee, [
            'old' => $oldValues,
            'new' => $employee->only(array_keys($data)),
        ]);

        return $employee->fresh();
    }

    /**
     * 办理离职
     *
     * @param  array<string, mixed>  $data
     *
     * @throws Throwable
     */
    public function resignEmployee(int $employeeId, array $data): void
    {
        DB::transaction(function () use ($employeeId, $data): void {
            $employee = Employee::findOrFail($employeeId);

            $employee->update(['status' => EmployeeStatus::Resigned]);
            $employee->resignation()->create($data);

            Log::info('员工离职办理完成', [
                'employee_id' => $employee->id,
                'code' => $employee->code,
            ]);

            $this->audit('employee_resigned', $employee, [
                'code' => $employee->code,
                'resignation_data' => $data,
            ]);
        });
    }

    /**
     * 员工转正
     */
    public function confirmEmployee(int $employeeId): Employee
    {
        $employee = Employee::findOrFail($employeeId);
        $employee->update(['status' => EmployeeStatus::Active]);

        Log::info('员工转正完成', [
            'employee_id' => $employee->id,
            'code' => $employee->code,
        ]);

        $this->audit('employee_confirmed', $employee, ['code' => $employee->code]);

        return $employee->fresh();
    }

    /**
     * 生成工号
     */
    public function generateEmployeeCode(): string
    {
        $prefix = config('kylin-hr.employee_code_prefix', 'EMP');
        $start = config('kylin-hr.employee_code_start', 1000);

        $lastEmployee = Employee::withTrashed()
            ->where('code', 'like', $prefix . '%')
            ->orderBy('code', 'desc')
            ->first();

        if ($lastEmployee) {
            $lastNumber = (int) substr($lastEmployee->code, strlen($prefix));
            return $prefix . str_pad((string) ($lastNumber + 1), 4, '0', STR_PAD_LEFT);
        }

        return $prefix . $start;
    }

    /**
     * 获取员工详情
     */
    public function getEmployeeDetail(int $id): Employee
    {
        return Employee::with([
            'department',
            'position',
            'activeContract',
            'socialInsurance',
        ])->findOrFail($id);
    }

    /**
     * 员工列表
     */
    public function listEmployees(array $filters = [], int $perPage = 20)
    {
        $query = Employee::with(['department', 'position']);

        if (!empty($filters['keyword'])) {
            $query->where(function ($q) use ($filters) {
                $q->where('name', 'like', "%{$filters['keyword']}%")
                  ->orWhere('code', 'like', "%{$filters['keyword']}%")
                  ->orWhere('phone', 'like', "%{$filters['keyword']}%");
            });
        }

        if (!empty($filters['department_id'])) {
            $query->where('department_id', $filters['department_id']);
        }

        if (!empty($filters['status'])) {
            $query->where('status', $filters['status']);
        }

        return $query->orderBy('id', 'desc')->paginate($perPage);
    }

    /**
     * 记录员工操作审计日志
     *
     * 依据《劳动合同法》和《个人信息保护法》，
     * 员工档案变更（入职/离职/转正/更新）需记录审计日志。
     * 不记录身份证号等敏感信息明文。
     */
    private function audit(string $event, Employee $employee, array $extra = []): void
    {
        if (! class_exists(\Kylin\AuditLog\Models\AuditLog::class)) {
            return;
        }

        try {
            \Kylin\AuditLog\Models\AuditLog::create([
                'event' => $event,
                'model_type' => Employee::class,
                'model_id' => $employee->id,
                'new_values' => $extra,
                'old_values' => null,
                'user_id' => auth()->id(),
                'ip' => request()?->ip(),
                'url' => request()?->fullUrl(),
                'tag' => 'hr-employee',
            ]);
        } catch (\Throwable $e) {
            logger()->warning('员工操作审计日志写入失败', [
                'error' => $e->getMessage(),
                'employee_id' => $employee->id,
                'event' => $event,
            ]);
        }
    }
}
