<?php
declare(strict_types=1);

namespace Ekesto\CacheInvalidator\Integrations\Forms;

/**
 * Value object carrying forms usage resolution output.
 */
final class FormsResolutionResult
{
    /**
     * @var int[]
     */
    private array $postIds;

    private bool $uncertain;

    private bool $uncertainDueToScanGap;

    private bool $uncertainDueToMetaTooLarge;

    private int $candidatesTotal;

    private int $candidatesScanned;

    /**
     * @var string[]
     */
    private array $fieldsScanned;

    /**
     * @var string[]
     */
    private array $targetIdentifiers;

    /**
     * Build a result object.
     *
     * @param int[]    $postIds Matched post IDs.
     * @param bool     $uncertain Uncertainty aggregate.
     * @param bool     $uncertainDueToScanGap Scan gap uncertainty.
     * @param bool     $uncertainDueToMetaTooLarge Meta size uncertainty.
     * @param int      $candidatesTotal Candidate count before cap.
     * @param int      $candidatesScanned Candidate count actually scanned.
     * @param string[] $fieldsScanned Fields scanned across candidates.
     * @param string[] $targetIdentifiers Target identifiers used for matching.
     */
    public function __construct(
        array $postIds,
        bool $uncertain,
        bool $uncertainDueToScanGap,
        bool $uncertainDueToMetaTooLarge,
        int $candidatesTotal,
        int $candidatesScanned,
        array $fieldsScanned,
        array $targetIdentifiers = []
    ) {
        $this->postIds = array_values(array_unique(array_filter(array_map('absint', $postIds), static fn(int $id): bool => $id > 0)));
        $this->uncertain = $uncertain;
        $this->uncertainDueToScanGap = $uncertainDueToScanGap;
        $this->uncertainDueToMetaTooLarge = $uncertainDueToMetaTooLarge;
        $this->candidatesTotal = max(0, $candidatesTotal);
        $this->candidatesScanned = max(0, $candidatesScanned);
        $this->fieldsScanned = array_values(array_unique(array_filter(array_map('strval', $fieldsScanned))));
        $this->targetIdentifiers = array_values(array_unique(array_filter(array_map('strval', $targetIdentifiers))));
    }

    /**
     * Return matched post IDs.
     *
     * @return int[]
     */
    public function postIds(): array
    {
        return $this->postIds;
    }

    /**
     * Return whether references were found.
     *
     * @return bool
     */
    public function hasReferences(): bool
    {
        return !empty($this->postIds);
    }

    /**
     * Return uncertainty aggregate.
     *
     * @return bool
     */
    public function uncertain(): bool
    {
        return $this->uncertain;
    }

    /**
     * Return scan gap uncertainty flag.
     *
     * @return bool
     */
    public function uncertainDueToScanGap(): bool
    {
        return $this->uncertainDueToScanGap;
    }

    /**
     * Return meta-too-large uncertainty flag.
     *
     * @return bool
     */
    public function uncertainDueToMetaTooLarge(): bool
    {
        return $this->uncertainDueToMetaTooLarge;
    }

    /**
     * Return diagnostics payload.
     *
     * @return array{candidates_total:int,candidates_scanned:int,fields_scanned:string[],target_identifiers:string[]}
     */
    public function diagnostics(): array
    {
        return [
            'candidates_total' => $this->candidatesTotal,
            'candidates_scanned' => $this->candidatesScanned,
            'fields_scanned' => $this->fieldsScanned,
            'target_identifiers' => $this->targetIdentifiers,
        ];
    }

    /**
     * Return target identifiers used for matching.
     *
     * @return string[]
     */
    public function targetIdentifiers(): array
    {
        return $this->targetIdentifiers;
    }

    /**
     * Return normalized array payload.
     *
     * @return array{post_ids:int[],has_references:bool,uncertain:bool,uncertain_due_to_scan_gap:bool,uncertain_due_to_meta_too_large:bool,candidates_total:int,candidates_scanned:int,fields_scanned:string[],target_identifiers:string[]}
     */
    public function toArray(): array
    {
        return [
            'post_ids' => $this->postIds(),
            'has_references' => $this->hasReferences(),
            'uncertain' => $this->uncertain(),
            'uncertain_due_to_scan_gap' => $this->uncertainDueToScanGap(),
            'uncertain_due_to_meta_too_large' => $this->uncertainDueToMetaTooLarge(),
            'candidates_total' => $this->candidatesTotal,
            'candidates_scanned' => $this->candidatesScanned,
            'fields_scanned' => $this->fieldsScanned,
            'target_identifiers' => $this->targetIdentifiers,
        ];
    }
}
