<?php

namespace App\Services\Inventory;

use App\Models\InventoryItem;
use App\Models\OperationRun;
use App\Models\ManagedEnvironment;
use App\Services\BackupScheduling\PolicyTypeResolver;
use App\Support\OperationCatalog;
use App\Support\OperationRunType;
use Illuminate\Database\Eloquent\Collection;

class InventoryMissingService
{
    public function __construct(
        private readonly InventorySelectionHasher $selectionHasher,
        private readonly PolicyTypeResolver $policyTypeResolver,
    ) {}

    /**
     * @param  array<string, mixed>  $selectionPayload
     * @return array{latestRun: OperationRun|null, missing: Collection<int, InventoryItem>, lowConfidence: bool}
     */
    public function missingForSelection(ManagedEnvironment $tenant, array $selectionPayload): array
    {
        $normalized = $this->selectionHasher->normalize($selectionPayload);
        $normalized['policy_types'] = $this->policyTypeResolver->filterRuntime($normalized['policy_types']);
        $selectionHash = $this->selectionHasher->hash($normalized);

        $latestRun = OperationRun::query()
            ->where('managed_environment_id', $tenant->getKey())
            ->whereIn('type', OperationCatalog::rawValuesForCanonical(OperationRunType::InventorySync->value))
            ->where('status', 'completed')
            ->where('context->selection_hash', $selectionHash)
            ->orderByDesc('completed_at')
            ->orderByDesc('id')
            ->first();

        if (! $latestRun) {
            return [
                'latestRun' => null,
                'missing' => InventoryItem::query()->whereRaw('1 = 0')->get(),
                'lowConfidence' => true,
            ];
        }

        $missingQuery = InventoryItem::query()
            ->where('managed_environment_id', $tenant->getKey())
            ->whereIn('policy_type', $normalized['policy_types'])
            ->where(function ($query) use ($latestRun): void {
                $query
                    ->whereNull('last_seen_operation_run_id')
                    ->orWhere('last_seen_operation_run_id', '!=', $latestRun->getKey());
            });

        $lowConfidence = $latestRun->outcome !== 'succeeded';

        return [
            'latestRun' => $latestRun,
            'missing' => $missingQuery->get(),
            'lowConfidence' => $lowConfidence,
        ];
    }
}
