<?php

namespace App\Services;

class EvaluationEngineService
{
    /**
     * @return array<string, float|int|string|bool|null>
     */
    public function getActiveRuleSet(): array
    {
        $rule = db_connect()
            ->table('evaluation_rules')
            ->where('is_active', 1)
            ->orderBy('scope_type', 'ASC')
            ->orderBy('id', 'DESC')
            ->get()
            ->getRowArray();

        if ($rule !== null) {
            return $rule;
        }

        return [
            'almost_ready_threshold' => 3.5,
            'ready_threshold' => 4.0,
            'minimum_critical_threshold' => 3.0,
        ];
    }

    /**
     * @param array<int, array<string, float|int|bool|null>> $criteriaScores
     * @param array<string, float|int|string|bool|null> $rules
     * @return array{final_score: float, final_status: string, promotion_signal: bool}
     */
    public function evaluate(array $criteriaScores, array $rules): array
    {
        $finalScore = $this->calculateFinalScore($criteriaScores);
        $status     = $this->calculateStatus($finalScore, $criteriaScores, $rules);

        return [
            'final_score' => $finalScore,
            'final_status' => $status,
            'promotion_signal' => $this->isEligibleForAdvancement($finalScore, $criteriaScores, $rules),
        ];
    }

    /**
     * @param array<int, array<string, float|int|bool|null>> $criteriaScores
     */
    public function calculateFinalScore(array $criteriaScores): float
    {
        $weightedScore = 0.0;
        $weightTotal   = 0.0;

        foreach ($criteriaScores as $criterion) {
            $score  = (float) ($criterion['score'] ?? 0);
            $weight = (float) ($criterion['weight'] ?? 1);

            $weightedScore += $score * $weight;
            $weightTotal   += $weight;
        }

        if ($weightTotal === 0.0) {
            return 0.0;
        }

        return round($weightedScore / $weightTotal, 2);
    }

    /**
     * @param array<int, array<string, float|int|bool|null>> $criteriaScores
     * @param array<string, float|int|string|bool|null> $rules
     */
    public function calculateStatus(float $finalScore, array $criteriaScores, array $rules): string
    {
        $readyThreshold           = (float) ($rules['ready_threshold'] ?? 4.0);
        $almostReadyThreshold     = (float) ($rules['almost_ready_threshold'] ?? 3.5);
        $minimumCriticalThreshold = (float) ($rules['minimum_critical_threshold'] ?? 3.0);

        foreach ($criteriaScores as $criterion) {
            $isCritical = (bool) ($criterion['is_critical'] ?? false);
            $score      = (float) ($criterion['score'] ?? 0);

            if ($isCritical && $score < $minimumCriticalThreshold) {
                return $finalScore >= $almostReadyThreshold ? 'ALMOST READY' : 'HOLD';
            }
        }

        if ($finalScore >= $readyThreshold) {
            return 'READY';
        }

        if ($finalScore >= $almostReadyThreshold) {
            return 'ALMOST READY';
        }

        return 'HOLD';
    }

    /**
     * @param array<int, array<string, float|int|bool|null>> $criteriaScores
     * @param array<string, float|int|string|bool|null> $rules
     */
    public function isEligibleForAdvancement(float $finalScore, array $criteriaScores, array $rules): bool
    {
        return $this->calculateStatus($finalScore, $criteriaScores, $rules) === 'READY';
    }
}
