<?php

declare(strict_types=1);

namespace App\Framework\Waf\ValueObjects;

use App\Framework\Waf\Detection;

/**
 * Collection of security detections from WAF layers
 */
final readonly class DetectionCollection implements \IteratorAggregate, \Countable
{
    /** @param Detection[] $detections */
    public function __construct(
        public array $detections
    ) {
    }

    /**
     * Create empty detection collection
     */
    public static function empty(): self
    {
        return new self([]);
    }

    /**
     * Create collection from single detection
     */
    public static function single(Detection $detection): self
    {
        return new self([$detection]);
    }

    /**
     * Create collection from array of detections
     */
    public static function fromArray(array $detections): self
    {
        // Validate all items are Detection instances
        foreach ($detections as $detection) {
            if (! $detection instanceof Detection) {
                throw new \InvalidArgumentException('All items must be Detection instances');
            }
        }

        return new self($detections);
    }

    /**
     * Get number of detections
     */
    public function count(): int
    {
        return count($this->detections);
    }

    /**
     * Check if collection is empty
     */
    public function isEmpty(): bool
    {
        return empty($this->detections);
    }

    /**
     * Check if collection has any detections
     */
    public function hasDetections(): bool
    {
        return ! $this->isEmpty();
    }

    /**
     * Add detection to collection
     */
    public function add(Detection $detection): self
    {
        return new self([...$this->detections, $detection]);
    }

    /**
     * Merge with another collection
     */
    public function merge(self $other): self
    {
        return new self([...$this->detections, ...$other->detections]);
    }

    /**
     * Filter detections by severity
     */
    public function filterBySeverity(DetectionSeverity $severity): self
    {
        $filtered = array_filter(
            $this->detections,
            fn (Detection $detection) => $detection->severity === $severity
        );

        return new self(array_values($filtered));
    }

    /**
     * Filter detections by category
     */
    public function filterByCategory(DetectionCategory $category): self
    {
        $filtered = array_filter(
            $this->detections,
            fn (Detection $detection) => $detection->category === $category
        );

        return new self(array_values($filtered));
    }

    /**
     * Get highest severity detection
     */
    public function getHighestSeverity(): ?Detection
    {
        if ($this->isEmpty()) {
            return null;
        }

        $highest = $this->detections[0];
        foreach ($this->detections as $detection) {
            if ($detection->severity->isHigherThan($highest->severity)) {
                $highest = $detection;
            }
        }

        return $highest;
    }

    /**
     * Get all unique categories in collection
     */
    public function getCategories(): array
    {
        $categories = array_map(
            fn (Detection $detection) => $detection->category,
            $this->detections
        );

        return array_unique($categories, SORT_REGULAR);
    }

    /**
     * Convert to array for serialization
     */
    public function toArray(): array
    {
        return array_map(
            fn (Detection $detection) => $detection->toArray(),
            $this->detections
        );
    }

    /**
     * Get iterator for foreach loops
     */
    public function getIterator(): \ArrayIterator
    {
        return new \ArrayIterator($this->detections);
    }
}
