<?php

declare(strict_types=1);

namespace App\Framework\Queue\MachineLearning\ValueObjects;

/**
 * Job Features - 8-Dimensional Feature Vector for Job Anomaly Detection
 *
 * Extracted behavioral features from job execution sequences
 * for machine learning-based anomaly detection.
 *
 * Features (all normalized to 0.0-1.0):
 * 1. execution_time_variance - Variance in execution times (stability)
 * 2. memory_usage_pattern - Memory consumption pattern (resource efficiency)
 * 3. retry_frequency - How often jobs retry (reliability indicator)
 * 4. failure_rate - Percentage of failed executions (quality indicator)
 * 5. queue_depth_correlation - Job volume impact on performance
 * 6. dependency_chain_complexity - Estimated execution dependencies
 * 7. payload_size_anomaly - Unusual payload sizes (data anomaly)
 * 8. execution_timing_regularity - Execution time consistency (bot detection)
 *
 * Immutable value object following framework patterns.
 */
final readonly class JobFeatures
{
    /**
     * @param float $executionTimeVariance Execution time variance (0.0-1.0, higher = more unstable)
     * @param float $memoryUsagePattern Memory usage pattern score (0.0-1.0, higher = more anomalous)
     * @param float $retryFrequency Retry frequency (0.0-1.0, higher = more retries)
     * @param float $failureRate Failure rate (0.0-1.0)
     * @param float $queueDepthCorrelation Queue depth impact on performance (0.0-1.0)
     * @param float $dependencyChainComplexity Dependency complexity estimate (0.0-1.0)
     * @param float $payloadSizeAnomaly Payload size anomaly score (0.0-1.0)
     * @param float $executionTimingRegularity Execution timing regularity (0.0-1.0, higher = more regular/bot-like)
     */
    public function __construct(
        public float $executionTimeVariance,
        public float $memoryUsagePattern,
        public float $retryFrequency,
        public float $failureRate,
        public float $queueDepthCorrelation,
        public float $dependencyChainComplexity,
        public float $payloadSizeAnomaly,
        public float $executionTimingRegularity
    ) {
        // Validation: All features must be normalized (0.0-1.0)
        foreach ($this->toArray() as $name => $value) {
            if ($value < 0.0 || $value > 1.0) {
                throw new \InvalidArgumentException(
                    sprintf('Feature "%s" must be normalized (0.0-1.0), got: %.4f', $name, $value)
                );
            }
        }
    }

    /**
     * Create features with all zeros (baseline)
     */
    public static function zero(): self
    {
        return new self(
            executionTimeVariance: 0.0,
            memoryUsagePattern: 0.0,
            retryFrequency: 0.0,
            failureRate: 0.0,
            queueDepthCorrelation: 0.0,
            dependencyChainComplexity: 0.0,
            payloadSizeAnomaly: 0.0,
            executionTimingRegularity: 0.0
        );
    }

    /**
     * Get feature names in order
     *
     * @return array<string>
     */
    public static function getFeatureNames(): array
    {
        return [
            'execution_time_variance',
            'memory_usage_pattern',
            'retry_frequency',
            'failure_rate',
            'queue_depth_correlation',
            'dependency_chain_complexity',
            'payload_size_anomaly',
            'execution_timing_regularity',
        ];
    }

    /**
     * Convert to feature vector array
     *
     * @return array<float>
     */
    public function toVector(): array
    {
        return [
            $this->executionTimeVariance,
            $this->memoryUsagePattern,
            $this->retryFrequency,
            $this->failureRate,
            $this->queueDepthCorrelation,
            $this->dependencyChainComplexity,
            $this->payloadSizeAnomaly,
            $this->executionTimingRegularity,
        ];
    }

    /**
     * Convert to associative array
     *
     * @return array<string, float>
     */
    public function toArray(): array
    {
        return [
            'execution_time_variance' => $this->executionTimeVariance,
            'memory_usage_pattern' => $this->memoryUsagePattern,
            'retry_frequency' => $this->retryFrequency,
            'failure_rate' => $this->failureRate,
            'queue_depth_correlation' => $this->queueDepthCorrelation,
            'dependency_chain_complexity' => $this->dependencyChainComplexity,
            'payload_size_anomaly' => $this->payloadSizeAnomaly,
            'execution_timing_regularity' => $this->executionTimingRegularity,
        ];
    }

    /**
     * Calculate Euclidean distance to other feature vector
     */
    public function distanceTo(self $other): float
    {
        $sumSquaredDifferences = 0.0;

        $thisVector = $this->toVector();
        $otherVector = $other->toVector();

        for ($i = 0; $i < 8; $i++) {
            $diff = $thisVector[$i] - $otherVector[$i];
            $sumSquaredDifferences += $diff * $diff;
        }

        return sqrt($sumSquaredDifferences);
    }

    /**
     * Calculate Manhattan distance to other feature vector
     */
    public function manhattanDistanceTo(self $other): float
    {
        $sumAbsDifferences = 0.0;

        $thisVector = $this->toVector();
        $otherVector = $other->toVector();

        for ($i = 0; $i < 8; $i++) {
            $sumAbsDifferences += abs($thisVector[$i] - $otherVector[$i]);
        }

        return $sumAbsDifferences;
    }

    /**
     * Check if features indicate high failure risk
     * (heuristic: high failure rate + high retry frequency)
     */
    public function indicatesHighFailureRisk(): bool
    {
        return $this->failureRate > 0.3 && $this->retryFrequency > 0.5;
    }

    /**
     * Check if features indicate performance degradation
     * (heuristic: high execution variance + memory pattern anomaly)
     */
    public function indicatesPerformanceDegradation(): bool
    {
        return $this->executionTimeVariance > 0.6 && $this->memoryUsagePattern > 0.6;
    }

    /**
     * Check if features indicate resource exhaustion
     * (heuristic: high queue depth correlation + memory anomaly)
     */
    public function indicatesResourceExhaustion(): bool
    {
        return $this->queueDepthCorrelation > 0.7 && $this->memoryUsagePattern > 0.7;
    }

    /**
     * Check if features indicate automated/bot-like execution
     * (heuristic: very high timing regularity + low variance)
     */
    public function indicatesAutomatedExecution(): bool
    {
        return $this->executionTimingRegularity > 0.9 && $this->executionTimeVariance < 0.1;
    }

    /**
     * Check if features indicate data processing anomaly
     * (heuristic: high payload size anomaly + high memory pattern)
     */
    public function indicatesDataProcessingAnomaly(): bool
    {
        return $this->payloadSizeAnomaly > 0.7 && $this->memoryUsagePattern > 0.6;
    }

    /**
     * Get anomaly indicators as array
     *
     * @return array<string, bool>
     */
    public function getAnomalyIndicators(): array
    {
        return [
            'high_failure_risk' => $this->indicatesHighFailureRisk(),
            'performance_degradation' => $this->indicatesPerformanceDegradation(),
            'resource_exhaustion' => $this->indicatesResourceExhaustion(),
            'automated_execution' => $this->indicatesAutomatedExecution(),
            'data_processing_anomaly' => $this->indicatesDataProcessingAnomaly(),
        ];
    }

    /**
     * Get highest feature value and name
     *
     * @return array{name: string, value: float}
     */
    public function getHighestFeature(): array
    {
        $features = $this->toArray();
        $maxValue = max($features);
        $maxName = array_search($maxValue, $features, true);

        return [
            'name' => (string) $maxName,
            'value' => $maxValue,
        ];
    }

    /**
     * Get top N features by value
     *
     * @return array<string, float>
     */
    public function getTopFeatures(int $n = 3): array
    {
        $features = $this->toArray();
        arsort($features);

        return array_slice($features, 0, $n, true);
    }

    /**
     * Create debugging representation
     */
    public function __toString(): string
    {
        $top = $this->getTopFeatures(3);
        $topStr = implode(', ', array_map(
            fn($name, $value) => sprintf('%s=%.2f', $name, $value),
            array_keys($top),
            $top
        ));

        return sprintf('JobFeatures[%s]', $topStr);
    }
}
