"""
questionnaires.py
------------------
Definitions and scoring logic for the three validated screening instruments
used by MindScreen AI:

    * PHQ-9  (Patient Health Questionnaire-9)   -> Depression
    * GAD-7  (Generalized Anxiety Disorder-7)   -> Anxiety
    * PSS-10 (Perceived Stress Scale-10)        -> Stress

IMPORTANT: These are the *public, validated instruments* reproduced for
research/screening use. This module only handles scoring mechanics. It does
NOT diagnose. All outputs must be presented to end users with the standard
disclaimer that this is a screening aid, not a diagnostic tool.
"""

from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, List, Optional


class Severity(str, Enum):
    MINIMAL = "minimal"
    MILD = "mild"
    MODERATE = "moderate"
    MODERATELY_SEVERE = "moderately_severe"
    SEVERE = "severe"
    LOW = "low"          # used for PSS-10
    HIGH = "high"         # used for PSS-10


# ---------------------------------------------------------------------------
# PHQ-9 (Depression) — 0 (Not at all) to 3 (Nearly every day), 9 items
# ---------------------------------------------------------------------------
PHQ9_ITEMS: List[str] = [
    "Little interest or pleasure in doing things",
    "Feeling down, depressed, or hopeless",
    "Trouble falling or staying asleep, or sleeping too much",
    "Feeling tired or having little energy",
    "Poor appetite or overeating",
    "Feeling bad about yourself, or that you are a failure, or have let "
    "yourself or your family down",
    "Trouble concentrating on things, such as reading or watching TV",
    "Moving or speaking noticeably slowly, or being fidgety/restless",
    "Thoughts that you would be better off dead, or of hurting yourself "
    "in some way",
]
PHQ9_SUICIDE_ITEM_INDEX = 8  # zero-indexed item 9 — always triggers safety check if > 0

# ---------------------------------------------------------------------------
# GAD-7 (Anxiety) — 0 (Not at all) to 3 (Nearly every day), 7 items
# ---------------------------------------------------------------------------
GAD7_ITEMS: List[str] = [
    "Feeling nervous, anxious, or on edge",
    "Not being able to stop or control worrying",
    "Worrying too much about different things",
    "Trouble relaxing",
    "Being so restless that it is hard to sit still",
    "Becoming easily annoyed or irritable",
    "Feeling afraid, as if something awful might happen",
]

# ---------------------------------------------------------------------------
# PSS-10 (Perceived Stress) — 0 (Never) to 4 (Very often), 10 items
# Items 4, 5, 7, 8 (zero-indexed: 3, 4, 6, 7) are reverse-scored.
# ---------------------------------------------------------------------------
PSS10_ITEMS: List[str] = [
    "Been upset because of something that happened unexpectedly",
    "Felt that you were unable to control the important things in your life",
    "Felt nervous and stressed",
    "Felt confident about your ability to handle your personal problems",
    "Felt that things were going your way",
    "Found that you could not cope with all the things you had to do",
    "Been able to control irritations in your life",
    "Felt that you were on top of things",
    "Been angered because of things outside of your control",
    "Felt difficulties were piling up so high that you could not overcome them",
]
PSS10_REVERSE_INDICES = {3, 4, 6, 7}  # zero-indexed


@dataclass
class QuestionnaireResult:
    name: str
    raw_score: int
    max_score: int
    severity: Severity
    flagged_items: Dict[int, int] = field(default_factory=dict)  # index -> response

    @property
    def normalized_score(self) -> float:
        """Score rescaled to 0-100 for combination with NLP signals."""
        return round(100 * self.raw_score / self.max_score, 1)


def score_phq9(responses: List[int]) -> QuestionnaireResult:
    _validate_responses(responses, len(PHQ9_ITEMS), max_option=3, name="PHQ-9")
    raw = sum(responses)
    if raw <= 4:
        severity = Severity.MINIMAL
    elif raw <= 9:
        severity = Severity.MILD
    elif raw <= 14:
        severity = Severity.MODERATE
    elif raw <= 19:
        severity = Severity.MODERATELY_SEVERE
    else:
        severity = Severity.SEVERE

    flagged = {}
    if responses[PHQ9_SUICIDE_ITEM_INDEX] > 0:
        flagged[PHQ9_SUICIDE_ITEM_INDEX] = responses[PHQ9_SUICIDE_ITEM_INDEX]

    return QuestionnaireResult(
        name="PHQ-9", raw_score=raw, max_score=27, severity=severity,
        flagged_items=flagged,
    )


def score_gad7(responses: List[int]) -> QuestionnaireResult:
    _validate_responses(responses, len(GAD7_ITEMS), max_option=3, name="GAD-7")
    raw = sum(responses)
    if raw <= 4:
        severity = Severity.MINIMAL
    elif raw <= 9:
        severity = Severity.MILD
    elif raw <= 14:
        severity = Severity.MODERATE
    else:
        severity = Severity.SEVERE

    return QuestionnaireResult(name="GAD-7", raw_score=raw, max_score=21, severity=severity)


def score_pss10(responses: List[int]) -> QuestionnaireResult:
    _validate_responses(responses, len(PSS10_ITEMS), max_option=4, name="PSS-10")
    adjusted = [
        (4 - r) if i in PSS10_REVERSE_INDICES else r
        for i, r in enumerate(responses)
    ]
    raw = sum(adjusted)
    if raw <= 13:
        severity = Severity.LOW
    elif raw <= 26:
        severity = Severity.MODERATE
    else:
        severity = Severity.HIGH

    return QuestionnaireResult(name="PSS-10", raw_score=raw, max_score=40, severity=severity)


def _validate_responses(responses: List[int], expected_len: int, max_option: int, name: str) -> None:
    if len(responses) != expected_len:
        raise ValueError(
            f"{name} requires exactly {expected_len} responses, got {len(responses)}"
        )
    for r in responses:
        if not isinstance(r, int) or r < 0 or r > max_option:
            raise ValueError(
                f"{name} responses must be integers between 0 and {max_option}, got {r}"
            )


# ---------------------------------------------------------------------------
# Response-option labels shown to the user when a question is asked
# conversationally (rather than as a rigid form).
# ---------------------------------------------------------------------------
FREQUENCY_LABELS_0_3 = {
    0: "not at all",
    1: "several days",
    2: "more than half the days",
    3: "nearly every day",
}

FREQUENCY_LABELS_0_4 = {
    0: "never",
    1: "almost never",
    2: "sometimes",
    3: "fairly often",
    4: "very often",
}
