<?php

namespace App\Modules\HR\Assets\Services;

use App\Modules\HR\Assets\DTOs\AssetWriteData;
use App\Modules\HR\Assets\Models\Asset;
use App\Modules\HR\Assets\Repositories\AssetRepository;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class AssetService
{
    public function __construct(private readonly AssetRepository $assets) {}

    public function create(int $tenantId, AssetWriteData $data): Asset
    {
        return $this->assets->create(array_merge($data->toArray(), [
            'tenant_id' => $tenantId,
            'status' => $data->values['status'] ?? 'available',
        ]));
    }

    public function update(Asset $asset, AssetWriteData $data): Asset
    {
        return $this->assets->update($asset, $data->toArray());
    }

    public function assign(Asset $asset, int $employeeId, ?string $notes): Asset
    {
        if ($asset->status !== 'available') {
            throw ValidationException::withMessages(['employee_id' => __('assets.validation.not_available')]);
        }

        return DB::transaction(function () use ($asset, $employeeId, $notes): Asset {
            $this->assets->createAssignment([
                'tenant_id' => $asset->tenant_id, 'employee_id' => $employeeId,
                'asset_code' => $asset->asset_code, 'asset_name' => $asset->name,
                'category' => $asset->category, 'assigned_at' => today(),
                'status' => 'assigned', 'notes' => $notes, 'external_asset_id' => $asset->id,
                'assigned_by' => auth()->id(),
            ]);
            $this->record($asset, $employeeId, 'assign', $notes);

            return $this->assets->update($asset, ['status' => 'assigned', 'current_employee_id' => $employeeId]);
        });
    }

    public function transfer(Asset $asset, int $employeeId, ?string $notes): Asset
    {
        if ($asset->status !== 'assigned') {
            throw ValidationException::withMessages(['employee_id' => __('assets.validation.not_assigned')]);
        }

        return DB::transaction(function () use ($asset, $employeeId, $notes): Asset {
            $this->closeAssignment($asset);
            $this->assets->createAssignment([
                'tenant_id' => $asset->tenant_id, 'employee_id' => $employeeId,
                'asset_code' => $asset->asset_code, 'asset_name' => $asset->name,
                'category' => $asset->category, 'assigned_at' => today(), 'status' => 'assigned',
                'notes' => $notes, 'external_asset_id' => $asset->id, 'assigned_by' => auth()->id(),
            ]);
            $this->record($asset, $employeeId, 'transfer', $notes);

            return $this->assets->update($asset, ['current_employee_id' => $employeeId]);
        });
    }

    public function return(Asset $asset, ?string $notes): Asset
    {
        return $this->release($asset, 'return', 'available', $notes);
    }

    public function damage(Asset $asset, ?string $notes): Asset
    {
        return $this->release($asset, 'damage', 'damaged', $notes);
    }

    private function release(Asset $asset, string $action, string $status, ?string $notes): Asset
    {
        return DB::transaction(function () use ($asset, $action, $status, $notes): Asset {
            $employeeId = $asset->current_employee_id;
            $this->closeAssignment($asset);
            $this->record($asset, $employeeId, $action, $notes);

            return $this->assets->update($asset, ['status' => $status, 'current_employee_id' => null]);
        });
    }

    private function closeAssignment(Asset $asset): void
    {
        $assignment = $this->assets->activeAssignment((int) $asset->id);
        if ($assignment !== null) {
            $this->assets->updateAssignment($assignment, ['status' => 'returned', 'returned_at' => today()]);
        }
    }

    private function record(Asset $asset, ?int $employeeId, string $action, ?string $notes): void
    {
        $this->assets->movement([
            'asset_id' => $asset->id, 'employee_id' => $employeeId,
            'action' => $action, 'notes' => $notes, 'created_by' => auth()->id(),
        ]);
    }
}
