<?php

declare(strict_types=1);

namespace Tournament\Scoring;

use RuntimeException;

final class PlacementKillsStrategy implements ScoringStrategy
{
    /**
     * Placement points.
     *
     * Index = placement
     * Value = points
     */
    private const PLACEMENT_POINTS = [
        1  => 12,
        2  => 9,
        3  => 8,
        4  => 7,
        5  => 6,
        6  => 5,
        7  => 4,
        8  => 3,
        9  => 2,
        10 => 1,
    ];

    /**
     * Points awarded for each kill.
     */
    private const KILL_POINTS = 1;

    /**
     * Calculate final Battle Royale score.
     *
     * Formula:
     *
     * Final Score =
     * Placement Points + Kill Points
     */
    public function calculateScore(
        array $result
    ): float {
        $placement = $this->getPlacement(
            $result
        );

        $kills = $this->getKills(
            $result
        );

        $placementPoints =
            self::PLACEMENT_POINTS[$placement] ?? 0;

        $killPoints =
            $kills * self::KILL_POINTS;

        return (float) (
            $placementPoints
            + $killPoints
        );
    }

    /**
     * Get validated placement.
     */
    private function getPlacement(
        array $result
    ): int {
        if (
            !isset($result['placement'])
            || $result['placement'] === null
        ) {
            throw new RuntimeException(
                'Placement is required.'
            );
        }

        if (!is_numeric($result['placement'])) {
            throw new RuntimeException(
                'Placement must be numeric.'
            );
        }

        $placement =
            (int) $result['placement'];

        if ($placement < 1) {
            throw new RuntimeException(
                'Placement must be greater than zero.'
            );
        }

        return $placement;
    }

    /**
     * Get validated kills.
     */
    private function getKills(
        array $result
    ): int {
        if (
            !isset($result['kills'])
            || $result['kills'] === null
        ) {
            throw new RuntimeException(
                'Kills are required.'
            );
        }

        if (!is_numeric($result['kills'])) {
            throw new RuntimeException(
                'Kills must be numeric.'
            );
        }

        $kills =
            (int) $result['kills'];

        if ($kills < 0) {
            throw new RuntimeException(
                'Kills cannot be negative.'
            );
        }

        return $kills;
    }
}