<?php

namespace App\Http\Controllers\Api\V1\HR;

use App\Domain\HR\Enums\EmployeeStatus;
use App\Domain\HR\Models\Employee;
use App\Domain\HR\Services\EmployeeService;
use App\Domain\Identity\Services\ScopeGuard;
use App\Http\Controllers\Controller;
use App\Http\Requests\HR\StoreEmployeeRequest;
use App\Http\Requests\HR\UpdateEmployeeRequest;
use App\Http\Resources\EmployeeResource;
use App\Support\ApiResponse;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class EmployeeController extends Controller
{
    public function __construct(
        private readonly EmployeeService $employees,
        private readonly ScopeGuard $scopes,
    ) {}

    public function index(Request $request): JsonResponse
    {
        $this->authorize('viewAny', Employee::class);

        $query = Employee::query()->with(['branch:id,uuid,name', 'department:id,uuid,name']);

        // The scope of `hr.view` decides the rows, never a client-side filter.
        $this->scopes->apply($query, $request->user(), 'hr.view');

        $employees = $query
            ->when($request->filled('search'), function ($builder) use ($request) {
                $search = '%'.$request->string('search').'%';
                $builder->where(fn ($q) => $q
                    ->where('full_name', 'like', $search)
                    ->orWhere('employee_code', 'like', $search)
                    ->orWhere('mobile', 'like', $search)
                    ->orWhere('email', 'like', $search));
            })
            ->when($request->filled('status'), fn ($builder) => $builder->where('status', $request->string('status')))
            ->when($request->boolean('employed_only'), fn ($builder) => $builder->employed())
            ->orderBy($request->string('sort_by', 'full_name')->toString() === 'joining_date' ? 'joining_date' : 'full_name')
            ->paginate($request->integer('per_page', 25));

        return ApiResponse::success(
            EmployeeResource::collection($employees),
            meta: ['statuses' => $this->statusOptions()],
        );
    }

    public function show(Employee $employee): JsonResponse
    {
        $this->authorize('view', $employee);

        $employee->load(['branch:id,uuid,name', 'department:id,uuid,name', 'manager:id,uuid,full_name', 'user:id,uuid,email']);

        return ApiResponse::success(new EmployeeResource($employee));
    }

    public function store(StoreEmployeeRequest $request): JsonResponse
    {
        $this->authorize('create', Employee::class);

        $attributes = $request->modelAttributes();
        $attributes['company_id'] = $request->user()->company_id;
        $attributes['branch_id'] ??= $request->user()->branch_id;

        $employee = $this->employees->create($attributes, $request->user());

        return ApiResponse::success(
            new EmployeeResource($employee->load(['branch:id,uuid,name', 'department:id,uuid,name'])),
            'Employee created successfully.',
            status: 201,
        );
    }

    public function update(UpdateEmployeeRequest $request, Employee $employee): JsonResponse
    {
        $this->authorize('update', $employee);

        $employee = $this->employees->update($employee, $request->modelAttributes(), $request->user());

        return ApiResponse::success(
            new EmployeeResource($employee->load(['branch:id,uuid,name', 'department:id,uuid,name'])),
            'Employee updated successfully.',
        );
    }

    public function destroy(Employee $employee): JsonResponse
    {
        $this->authorize('delete', $employee);

        // Soft delete: payroll and audit history must survive an employee leaving.
        $employee->delete();

        return ApiResponse::success(null, 'Employee archived successfully.');
    }

    /** @return array<int, array{value: string, label: string}> */
    private function statusOptions(): array
    {
        return array_map(
            fn (EmployeeStatus $status) => ['value' => $status->value, 'label' => $status->label()],
            EmployeeStatus::cases(),
        );
    }
}
