<?php

declare(strict_types=1);

namespace App\Support\Baselines\Compare;

use InvalidArgumentException;

final class CompareStrategyCapability
{
    /**
     * @param  list<string>  $domainKeys
     * @param  list<string>  $subjectClasses
     * @param  list<string>|'all'  $subjectTypeKeys
     */
    public function __construct(
        public readonly CompareStrategyKey $strategyKey,
        public readonly array $domainKeys,
        public readonly array $subjectClasses,
        public readonly array|string $subjectTypeKeys = 'all',
        public readonly bool $compareSupported = true,
        public readonly bool $active = true,
    ) {
        if ($this->domainKeys === [] || $this->subjectClasses === []) {
            throw new InvalidArgumentException('Compare strategy capabilities require at least one domain key and one subject class.');
        }

        if ($this->subjectTypeKeys !== 'all' && $this->subjectTypeKeys === []) {
            throw new InvalidArgumentException('Compare strategy capabilities must either support all subject type keys or at least one explicit subject type key.');
        }
    }

    /**
     * @param  array{domain_key?: mixed, subject_class?: mixed, subject_type_keys?: mixed}  $entry
     */
    public function supportsEntry(array $entry): bool
    {
        if (! $this->active || ! $this->compareSupported) {
            return false;
        }

        $domainKey = is_string($entry['domain_key'] ?? null) ? trim((string) $entry['domain_key']) : '';
        $subjectClass = is_string($entry['subject_class'] ?? null) ? trim((string) $entry['subject_class']) : '';
        $subjectTypeKeys = is_array($entry['subject_type_keys'] ?? null)
            ? array_values(array_filter($entry['subject_type_keys'], 'is_string'))
            : [];

        if ($domainKey === '' || $subjectClass === '' || $subjectTypeKeys === []) {
            return false;
        }

        if (! in_array($domainKey, $this->domainKeys, true) || ! in_array($subjectClass, $this->subjectClasses, true)) {
            return false;
        }

        if ($this->subjectTypeKeys === 'all') {
            return true;
        }

        return array_diff($subjectTypeKeys, $this->subjectTypeKeys) === [];
    }

    /**
     * @return array{
     *   strategy_key: string,
     *   domain_keys: list<string>,
     *   subject_classes: list<string>,
     *   subject_type_keys: list<string>|'all',
     *   compare_supported: bool,
     *   active: bool
     * }
     */
    public function toArray(): array
    {
        return [
            'strategy_key' => $this->strategyKey->value,
            'domain_keys' => $this->domainKeys,
            'subject_classes' => $this->subjectClasses,
            'subject_type_keys' => $this->subjectTypeKeys,
            'compare_supported' => $this->compareSupported,
            'active' => $this->active,
        ];
    }
}