<?php

declare(strict_types=1);

use App\Framework\Core\ValueObjects\Percentage;
use App\Framework\Core\ValueObjects\Score;
use App\Framework\Core\ValueObjects\ScoreLevel;

describe('Score Value Object', function () {

    it('creates score with valid value', function () {
        $score = new Score(0.75);

        expect($score->value())->toBe(0.75);
        expect($score->toLevel())->toBe(ScoreLevel::HIGH);
    });

    it('validates score bounds', function () {
        expect(fn () => new Score(-0.1))->toThrow(InvalidArgumentException::class);
        expect(fn () => new Score(1.1))->toThrow(InvalidArgumentException::class);
    });

    it('creates score from percentage', function () {
        $percentage = Percentage::from(80.0); // 80%
        $score = Score::fromPercentage($percentage);

        expect($score->value())->toBe(0.8);
    });

    it('converts to percentage', function () {
        $score = new Score(0.6);
        $percentage = $score->toPercentage();

        expect($percentage->getValue())->toBe(60.0); // 60%
    });

    it('determines correct levels', function () {
        expect((new Score(0.95))->toLevel())->toBe(ScoreLevel::CRITICAL);
        expect((new Score(0.8))->toLevel())->toBe(ScoreLevel::HIGH);
        expect((new Score(0.5))->toLevel())->toBe(ScoreLevel::MEDIUM);
        expect((new Score(0.1))->toLevel())->toBe(ScoreLevel::LOW);
    });

    it('combines scores correctly', function () {
        $score1 = new Score(0.8);
        $score2 = new Score(0.4);

        $combined = $score1->combine($score2, 0.6);

        expect($combined->value())->toBe(0.64); // 0.8 * 0.6 + 0.4 * 0.4
    });

    it('calculates weighted average', function () {
        $scores = [
            new Score(0.8),
            new Score(0.6),
            new Score(0.4),
        ];
        $weights = [0.5, 0.3, 0.2];

        $average = Score::weightedAverage($scores, $weights);

        expect($average->value())->toEqualWithDelta(0.66, 0.01); // 0.8*0.5 + 0.6*0.3 + 0.4*0.2
    });

    it('serializes and deserializes correctly', function () {
        $score = new Score(0.75);
        $array = $score->toArray();
        $restored = Score::fromArray($array);

        expect($restored->value())->toBe($score->value());
        expect($restored->toLevel())->toBe($score->toLevel());
    });

});
