<?php

namespace App\Services\Forecasting;

use App\Services\Forecasting\Contracts\ForecastFeature;
use InvalidArgumentException;

/**
 * Immutable list of features a model uses, plus a deterministic hash
 * for audit linking on backtests.model_version.
 *
 * Two FeatureSpec instances with the same feature names + same model
 * label produce the same hash, so retraining the same model
 * configuration overwrites the same `backtests` row (via UNIQUE on
 * model_version).
 */
final readonly class FeatureSpec
{
    /** @param array<int, ForecastFeature> $features */
    public function __construct(
        public string $modelLabel,
        public array $features,
    ) {
        foreach ($features as $f) {
            if (! $f instanceof ForecastFeature) {
                throw new InvalidArgumentException('Every spec entry must implement ForecastFeature');
            }
        }
    }

    /** @return array<int, string> */
    public function names(): array
    {
        return array_map(fn (ForecastFeature $f): string => $f->name(), $this->features);
    }

    public function modelVersion(): string
    {
        $names = $this->names();
        sort($names);
        $hash = substr(sha1(json_encode($names, JSON_THROW_ON_ERROR)), 0, 12);

        return $this->modelLabel.'-'.$hash;
    }

    /** @return array{model_label: string, features: array<int, string>} */
    public function toArray(): array
    {
        return [
            'model_label' => $this->modelLabel,
            'features' => $this->names(),
        ];
    }
}
