"""
camcops_server/tasks/apeqpt.py

===============================================================================

    Copyright (C) 2012, University of Cambridge, Department of Psychiatry.
    Created by Rudolf Cardinal (rnc1001@cam.ac.uk).

    This file is part of CamCOPS.

    CamCOPS is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    CamCOPS is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with CamCOPS. If not, see <https://www.gnu.org/licenses/>.

===============================================================================

- By Joe Kearney, Rudolf Cardinal.

"""

from typing import Dict, List, Optional

from pendulum import DateTime as Pendulum
from sqlalchemy.orm import Mapped
from sqlalchemy.sql.sqltypes import UnicodeText

from camcops_server.cc_modules.cc_constants import CssClass
from camcops_server.cc_modules.cc_fhir import (
    FHIRAnsweredQuestion,
    FHIRAnswerType,
    FHIRQuestionType,
)
from camcops_server.cc_modules.cc_html import tr_qa
from camcops_server.cc_modules.cc_request import CamcopsRequest
from camcops_server.cc_modules.cc_sqla_coltypes import (
    mapped_camcops_column,
    PendulumDateTimeAsIsoTextColType,
    ZERO_TO_ONE_CHECKER,
    ZERO_TO_TWO_CHECKER,
    ZERO_TO_FOUR_CHECKER,
)
from camcops_server.cc_modules.cc_summaryelement import SummaryElement
from camcops_server.cc_modules.cc_task import get_from_dict, Task


# =============================================================================
# APEQPT
# =============================================================================


class Apeqpt(Task):
    """
    Server implementation of the APEQPT task.
    """

    __tablename__ = "apeqpt"
    shortname = "APEQPT"
    provides_trackers = True

    # todo: remove q_datetime (here and in the C++) -- it duplicates when_created  # noqa
    q_datetime: Mapped[Optional[Pendulum]] = mapped_camcops_column(
        PendulumDateTimeAsIsoTextColType,
        comment="Date/time the assessment tool was completed",
    )

    N_CHOICE_QUESTIONS = 3
    q1_choice: Mapped[Optional[int]] = mapped_camcops_column(
        comment="Enough information was provided (0 no, 1 yes)",
        permitted_value_checker=ZERO_TO_ONE_CHECKER,
    )
    q2_choice: Mapped[Optional[int]] = mapped_camcops_column(
        comment="Treatment preference (0 no, 1 yes)",
        permitted_value_checker=ZERO_TO_ONE_CHECKER,
    )
    q3_choice: Mapped[Optional[int]] = mapped_camcops_column(
        comment="Preference offered (0 no, 1 yes, 2 N/A)",
        permitted_value_checker=ZERO_TO_TWO_CHECKER,
    )

    q1_satisfaction: Mapped[Optional[int]] = mapped_camcops_column(
        comment=(
            "Patient satisfaction (0 not at all satisfied - "
            "4 completely satisfied)"
        ),
        permitted_value_checker=ZERO_TO_FOUR_CHECKER,
    )
    q2_satisfaction: Mapped[Optional[str]] = mapped_camcops_column(
        UnicodeText, comment="Service experience"
    )

    MAIN_QUESTIONS = [
        "q_datetime",
        "q1_choice",
        "q2_choice",
        "q3_choice",
        "q1_satisfaction",
    ]

    @staticmethod
    def longname(req: "CamcopsRequest") -> str:
        _ = req.gettext
        return _(
            "Assessment Patient Experience Questionnaire "
            "for Psychological Therapies"
        )

    def is_complete(self) -> bool:
        if self.any_fields_none(self.MAIN_QUESTIONS):
            return False
        if not self.field_contents_valid():
            return False
        return True

    def get_summaries(self, req: CamcopsRequest) -> List[SummaryElement]:
        return self.standard_task_summary_fields()

    def get_task_html(self, req: CamcopsRequest) -> str:
        c_dict = {
            0: "0 — " + self.wxstring(req, "a0_choice"),
            1: "1 — " + self.wxstring(req, "a1_choice"),
            2: "2 — " + self.wxstring(req, "a2_choice"),
        }
        s_dict = {
            0: "0 — " + self.wxstring(req, "a0_satisfaction"),
            1: "1 — " + self.wxstring(req, "a1_satisfaction"),
            2: "2 — " + self.wxstring(req, "a2_satisfaction"),
            3: "3 — " + self.wxstring(req, "a3_satisfaction"),
            4: "4 — " + self.wxstring(req, "a4_satisfaction"),
        }
        q_a = ""
        for i in range(1, self.N_CHOICE_QUESTIONS + 1):
            nstr = str(i)
            q_a += tr_qa(
                self.wxstring(req, "q" + nstr + "_choice"),
                get_from_dict(c_dict, getattr(self, "q" + nstr + "_choice")),
            )

        q_a += tr_qa(
            self.wxstring(req, "q1_satisfaction"),
            get_from_dict(s_dict, self.q1_satisfaction),
        )
        q_a += tr_qa(
            self.wxstring(req, "q2_satisfaction"),
            self.q2_satisfaction,
            default="",
        )

        return f"""
            <div class="{CssClass.SUMMARY}">
                <table class="{CssClass.SUMMARY}">
                    {self.get_is_complete_tr(req)}
                </table>
            </div>
            <div class="{CssClass.EXPLANATION}">
                Patient satisfaction rating for service provided. The service
                is rated on choice offered and general satisfaction.
            </div>
            <table class="{CssClass.TASKDETAIL}">
                <tr>
                    <th width="60%">Question</th>
                    <th width="40%">Answer</th>
                </tr>
                {q_a}
            </table>
        """

    def get_fhir_questionnaire(
        self, req: "CamcopsRequest"
    ) -> List[FHIRAnsweredQuestion]:
        items = []  # type: List[FHIRAnsweredQuestion]

        yes_no_options = {}  # type: Dict[int, str]
        for index in range(2):
            yes_no_options[index] = self.wxstring(req, f"a{index}_choice")
        items.append(
            FHIRAnsweredQuestion(
                qname="q1_choice",
                qtext=self.wxstring(req, "q1_choice"),
                qtype=FHIRQuestionType.CHOICE,
                answer_type=FHIRAnswerType.INTEGER,
                answer=self.q1_choice,
                answer_options=yes_no_options,
            )
        )
        items.append(
            FHIRAnsweredQuestion(
                qname="q2_choice",
                qtext=self.wxstring(req, "q2_choice"),
                qtype=FHIRQuestionType.CHOICE,
                answer_type=FHIRAnswerType.INTEGER,
                answer=self.q2_choice,
                answer_options=yes_no_options,
            )
        )

        yes_no_na_options = yes_no_options.copy()
        yes_no_na_options[2] = self.wxstring(req, "a2_choice")
        items.append(
            FHIRAnsweredQuestion(
                qname="q3_choice",
                qtext=self.wxstring(req, "q3_choice"),
                qtype=FHIRQuestionType.CHOICE,
                answer_type=FHIRAnswerType.INTEGER,
                answer=self.q3_choice,
                answer_options=yes_no_na_options,
            )
        )

        satisfaction_options = {}  # type: Dict[int, str]
        for index in range(5):
            satisfaction_options[index] = self.wxstring(
                req, f"a{index}_satisfaction"
            )
        items.append(
            FHIRAnsweredQuestion(
                qname="q1_satisfaction",
                qtext=self.xstring(req, "q1_satisfaction"),
                qtype=FHIRQuestionType.CHOICE,
                answer_type=FHIRAnswerType.INTEGER,
                answer=self.q1_satisfaction,
                answer_options=satisfaction_options,
            )
        )

        items.append(
            FHIRAnsweredQuestion(
                qname="q2_satisfaction",
                qtext=self.xstring(req, "q2_satisfaction"),
                qtype=FHIRQuestionType.STRING,
                answer_type=FHIRAnswerType.STRING,
                answer=self.q2_satisfaction,
            )
        )

        return items
