<?php

namespace Modules\MedPortal\Services;

use Modules\MedPortal\Entities\MportalQuestionnaire;
use Modules\MedPortal\Entities\MportalQuestionnaireResponse;

/**
 * QuestionnaireService — scores standardized mental-health questionnaires
 * (SIFA Phase 8, patient_portal → health_tools → health_questionnaires).
 *
 * Implements the published PHQ-9 (0–27) and GAD-7 (0–21) scoring bands. The
 * band table is stored on each questionnaire's `scoring` JSON (seeded), so a
 * `custom` questionnaire can define its own bands and score without code
 * changes; PHQ-9 / GAD-7 severity strings follow the clinical standard.
 */
class QuestionnaireService
{
    /**
     * Standard PHQ-9 severity bands (total 0–27).
     * @var array<int,array{min:int,max:int,severity:string}>
     */
    public const PHQ9_BANDS = [
        ['min' => 0,  'max' => 4,  'severity' => 'minimal'],
        ['min' => 5,  'max' => 9,  'severity' => 'mild'],
        ['min' => 10, 'max' => 14, 'severity' => 'moderate'],
        ['min' => 15, 'max' => 19, 'severity' => 'moderately_severe'],
        ['min' => 20, 'max' => 27, 'severity' => 'severe'],
    ];

    /**
     * Standard GAD-7 severity bands (total 0–21).
     * @var array<int,array{min:int,max:int,severity:string}>
     */
    public const GAD7_BANDS = [
        ['min' => 0,  'max' => 4,  'severity' => 'minimal'],
        ['min' => 5,  'max' => 9,  'severity' => 'mild'],
        ['min' => 10, 'max' => 14, 'severity' => 'moderate'],
        ['min' => 15, 'max' => 21, 'severity' => 'severe'],
    ];

    /** PHQ-9 total >= this flags a patient on the dashboard. */
    public const PHQ9_FLAG_THRESHOLD = 15;

    /**
     * Score a set of answers against a questionnaire. Answers are an array of
     * integer item values (0–3 for PHQ-9/GAD-7). Returns [score, severity].
     *
     * @param  array<int,int|string>  $answers
     * @return array{score:int,severity:string}
     */
    public function score(MportalQuestionnaire $questionnaire, array $answers): array
    {
        $score = 0;
        foreach ($answers as $value) {
            $score += (int) $value;
        }

        $severity = $this->severityForScore($questionnaire, $score);

        return ['score' => $score, 'severity' => $severity];
    }

    /** Resolve the severity band string for a raw score. */
    public function severityForScore(MportalQuestionnaire $questionnaire, int $score): string
    {
        $bands = $this->bandsFor($questionnaire);

        foreach ($bands as $band) {
            if ($score >= (int) $band['min'] && $score <= (int) $band['max']) {
                return (string) $band['severity'];
            }
        }

        return 'unknown';
    }

    /**
     * Complete a response: store answers, computed score + severity, and stamp
     * completed_at.
     */
    public function complete(MportalQuestionnaireResponse $response, array $answers): MportalQuestionnaireResponse
    {
        $questionnaire = $response->questionnaire()->first();
        if (! $questionnaire) {
            throw new \RuntimeException('Response has no questionnaire.');
        }

        $result = $this->score($questionnaire, $answers);

        $response->answers      = array_values($answers);
        $response->score        = $result['score'];
        $response->severity     = $result['severity'];
        $response->completed_at = now();
        $response->save();

        return $response;
    }

    /** True when a completed PHQ-9 response is at/above the flag threshold. */
    public function isFlagged(MportalQuestionnaireResponse $response): bool
    {
        $q = $response->questionnaire()->first();
        if (! $q || $q->code !== 'phq9' || $response->score === null) {
            return false;
        }

        return (int) $response->score >= self::PHQ9_FLAG_THRESHOLD;
    }

    /**
     * Scoring bands for a questionnaire: prefer its own `scoring.bands` JSON,
     * else fall back to the built-in PHQ-9 / GAD-7 constants by code.
     *
     * @return array<int,array{min:int,max:int,severity:string}>
     */
    private function bandsFor(MportalQuestionnaire $questionnaire): array
    {
        $scoring = (array) $questionnaire->scoring;
        if (! empty($scoring['bands']) && is_array($scoring['bands'])) {
            return $scoring['bands'];
        }

        return match ($questionnaire->code) {
            'phq9'  => self::PHQ9_BANDS,
            'gad7'  => self::GAD7_BANDS,
            default => [],
        };
    }
}
