<?php

declare(strict_types=1);

namespace App\Services\Evidence;

use App\Models\EvidenceSnapshot;
use App\Support\Evidence\EvidenceCompletenessState;

final class EvidenceSnapshotResolver
{
    public function resolve(EvidenceResolutionRequest $request): EvidenceResolutionResult
    {
        $query = EvidenceSnapshot::query()
            ->with('items')
            ->where('workspace_id', $request->workspaceId)
            ->where('managed_environment_id', $request->tenantId)
            ->where('status', 'active')
            ->where(function ($query): void {
                $query->whereNull('expires_at')->orWhere('expires_at', '>', now());
            })
            ->latest('generated_at');

        if ($request->snapshotId !== null) {
            $query->whereKey($request->snapshotId);
        }

        $snapshot = $query->first();

        if (! $snapshot instanceof EvidenceSnapshot) {
            return EvidenceResolutionResult::missingSnapshot(['No active snapshot found.']);
        }

        $requiredDimensions = $request->requiredDimensions;
        $items = $snapshot->items->keyBy('dimension_key');
        $reasons = [];

        foreach ($requiredDimensions as $dimension) {
            $item = $items->get($dimension);

            if ($item === null) {
                $reasons[] = sprintf('Missing dimension: %s', $dimension);

                continue;
            }

            if ((string) $item->state === EvidenceCompletenessState::Missing->value) {
                $reasons[] = sprintf('Missing dimension: %s', $dimension);
            }

            if (! $request->allowStale && (string) $item->state === EvidenceCompletenessState::Stale->value) {
                $reasons[] = sprintf('Stale dimension: %s', $dimension);
            }
        }

        if ($reasons !== []) {
            return EvidenceResolutionResult::snapshotIneligible($snapshot, $reasons);
        }

        return EvidenceResolutionResult::resolved($snapshot, $requiredDimensions === [] ? $items->keys()->all() : $requiredDimensions);
    }
}
