"""Problem interaction events model definitions."""

import sys
from typing import List, Union

from pydantic import Json

from ralph.models.selector import selector

from ..browser import BaseBrowserModel
from ..server import BaseServerModel
from .fields.events import (
    EdxProblemHintDemandhintDisplayedEventField,
    EdxProblemHintFeedbackDisplayedEventField,
    ProblemCheckEventField,
    ProblemCheckFailEventField,
    ProblemRescoreEventField,
    ProblemRescoreFailEventField,
    ResetProblemEventField,
    ResetProblemFailEventField,
    SaveProblemFailEventField,
    SaveProblemSuccessEventField,
    ShowAnswerEventField,
    UIProblemResetEventField,
    UIProblemShowEventField,
)

if sys.version_info >= (3, 8):
    from typing import Literal
else:
    from typing_extensions import Literal


class EdxProblemHintDemandhintDisplayed(BaseServerModel):
    """Pydantic model for `edx.problem.hint.demandhint_displayed` statement.

    The server emits this statement when a user requests a hint for a problem.

    Attributes:
        event (dict): See EdxProblemHintDemandhintDisplayedEventField.
        event_type (str): Consists of the value `edx.problem.hint.demandhint_displayed`.
        page (str): Consists of the value `x_module`.
    """

    __selector__ = selector(
        event_source="server", event_type="edx.problem.hint.demandhint_displayed"
    )

    event: EdxProblemHintDemandhintDisplayedEventField
    event_type: Literal["edx.problem.hint.demandhint_displayed"]
    page: Literal["x_module"]


class EdxProblemHintFeedbackDisplayed(BaseServerModel):
    """Pydantic model for `edx.problem.hint.feedback_displayed` statement.

    The server emits this event when a user receives a hint after answering a problem.

    Attributes:
        event (dict): See EdxProblemHintFeedbackDisplayedEventField.
        event_type (str): Consists of the value `edx.problem.hint.feedback_displayed`.
        page (str): Consists of the value `x_module`.
    """

    __selector__ = selector(
        event_source="server", event_type="edx.problem.hint.feedback_displayed"
    )

    event: EdxProblemHintFeedbackDisplayedEventField
    event_type: Literal["edx.problem.hint.feedback_displayed"]
    page: Literal["x_module"]


class UIProblemCheck(BaseBrowserModel):
    """Pydantic model for `problem_check` statement.

    The browser emits this event when a user checks a problem.

    Attributes:
        event (str): Consists of values of problem being checked, styled as `GET`
            parameters.
        event_type (str): Consists of the value `problem_check`.
        name (str): Consists of the value `problem_check`.
    """

    __selector__ = selector(event_source="browser", event_type="problem_check")

    event: str
    event_type: Literal["problem_check"]
    name: Literal["problem_check"]


class ProblemCheck(BaseServerModel):
    """Pydantic model for `problem_check` statement.

    The server emits this event when a user checks a problem.

    Attributes:
        event (dict): See ProblemCheckEventField.
        event_type (str): Consists of the value `problem_check`.
        page (str): Consists of the value `x_module`.
    """

    __selector__ = selector(event_source="server", event_type="problem_check")

    event: ProblemCheckEventField
    event_type: Literal["problem_check"]
    page: Literal["x_module"]


class ProblemCheckFail(BaseServerModel):
    """Pydantic model for `problem_check_fail` statement.

    The server emits this event when a user checks a problem and a failure prevents the
    problem from being checked successfully.

    Attributes:
        event (dict): See ProblemCheckFailEventField.
        event_type (str): Consists of the value `problem_check_fail`.
        page (str): Consists of the value `x_module`.
    """

    __selector__ = selector(event_source="server", event_type="problem_check_fail")

    event: ProblemCheckFailEventField
    event_type: Literal["problem_check_fail"]
    page: Literal["x_module"]


class UIProblemGraded(BaseBrowserModel):
    """Pydantic model for `problem_graded` statement.

    The server emits this statement each time a user clicks <kbd>Check</kbd> for a
    problem and it is graded successfully.

    Attributes:
        event (list): See ProblemGradedEventField.
        event_type (str): Consists of the value `problem_graded`.
        name (str): Consists of the value `problem_graded`.
    """

    __selector__ = selector(event_source="browser", event_type="problem_graded")

    event: List[Union[str, Literal[None], None]]
    event_type: Literal["problem_graded"]
    name: Literal["problem_graded"]


class ProblemRescore(BaseServerModel):
    """Pydantic model for `problem_rescore` statement.

    The server emits this statement when a problem is successfully rescored.

    Attributes:
        event (dict): See ProblemRescoreEventField.
        event_type (str): Consists of the value `problem_rescore`.
        page (str): Consists of the value `x_module`.
    """

    __selector__ = selector(event_source="server", event_type="problem_rescore")

    event: ProblemRescoreEventField
    event_type: Literal["problem_rescore"]
    page: Literal["x_module"]


class ProblemRescoreFail(BaseServerModel):
    """Pydantic model for `problem_rescore_fail` statement.

    The server emits this statement when a problem cannot be successfully rescored.

    Attributes:
        event (dict): See ProblemRescoreFailEventField.
        event_type (str): Consists of the value `problem_rescore_fail`.
        page (str): Consists of the value `x_module`.
    """

    __selector__ = selector(event_source="server", event_type="problem_rescore_fail")

    event: ProblemRescoreFailEventField
    event_type: Literal["problem_rescore_fail"]
    page: Literal["x_module"]


class UIProblemReset(BaseBrowserModel):
    """Pydantic model for `problem_reset` statement.

    The browser emits problem_reset events when a user clicks <kbd>Reset</kbd> to reset
    the problem answer.

    Attributes:
        event (json): See ProblemResetEventField.
        event_type (str): Consists of the value `problem_reset`.
        name (str): Consists of the value `problem_reset`.
    """

    __selector__ = selector(event_source="browser", event_type="problem_reset")

    event: Union[
        str,
        Json[UIProblemResetEventField],
        UIProblemResetEventField,
    ]
    event_type: Literal["problem_reset"]
    name: Literal["problem_reset"]


class UIProblemSave(BaseBrowserModel):
    """Pydantic model for `problem_save` statement.

    The browser emits this statement when a user saves a problem.

    Attributes:
        event (str): Consists of all the answers saved for the problem.
        event_type (str): Consists of the value `problem_save`.
        name (str): Consists of the value `problem_save`.
    """

    __selector__ = selector(event_source="browser", event_type="problem_save")

    event: str
    event_type: Literal["problem_save"]
    name: Literal["problem_save"]


class UIProblemShow(BaseBrowserModel):
    """Pydantic model for `problem_show` statement.

    The browser emits this statement when the answer clicks <kbd>Show Answer</kbd> to
    show the problem answer.

    Attributes:
        event (json): See ProblemShowEventField.
        event_type (str): Consists of the value `problem_save`.
        name (str): Consists of the value `problem_save`.
    """

    __selector__ = selector(event_source="browser", event_type="problem_show")

    event: Union[
        Json[UIProblemShowEventField],
        UIProblemShowEventField,
    ]
    event_type: Literal["problem_show"]
    name: Literal["problem_show"]


class ResetProblem(BaseServerModel):
    """Pydantic model for `reset_problem` statement.

    The server emits this statement when a problem has been reset successfully.

    Attributes:
        event (dict): See ResetProblemEventField.
        event_type (str): Consists of the value `reset_problem`.
        page (str): Consists of the value `x_module`.
    """

    __selector__ = selector(event_source="server", event_type="reset_problem")

    event: ResetProblemEventField
    event_type: Literal["reset_problem"]
    page: Literal["x_module"]


class ResetProblemFail(BaseServerModel):
    """Pydantic model for `reset_problem_fail` statement.

    The server emits this statement when a problem cannot be reset successfully.

    Attributes:
        event (dict): See ResetProblemFailEventField.
        event_type (str): Consists of the value `reset_problem_fail`.
        page (str): Consists of the value `x_module`.
    """

    __selector__ = selector(event_source="server", event_type="reset_problem_fail")

    event: ResetProblemFailEventField
    event_type: Literal["reset_problem_fail"]
    page: Literal["x_module"]


class SaveProblemFail(BaseServerModel):
    """Pydantic model for `save_problem_fail` statement.

    The server emits this statement when a problem cannot be saved successfully.

    Attributes:
        event (dict): See SaveProblemFailEventField.
        event_type (str): Consists of the value `save_problem_fail`.
        page (str): Consists of the value `x_module`.
    """

    __selector__ = selector(event_source="server", event_type="save_problem_fail")

    event: SaveProblemFailEventField
    event_type: Literal["save_problem_fail"]
    page: Literal["x_module"]


class SaveProblemSuccess(BaseServerModel):
    """Pydantic model for `save_problem_success` statement.

    The server emits this statement when a problem is saved successfully.

    Attributes:
        event (dict): See SaveProblemSuccessEventField.
        event_type (str): Consists of the value `save_problem_success`.
        page (str): Consists of the value `x_module`.
    """

    __selector__ = selector(event_source="server", event_type="save_problem_success")

    event: SaveProblemSuccessEventField
    event_type: Literal["save_problem_success"]
    page: Literal["x_module"]


class ShowAnswer(BaseServerModel):
    """Pydantic model for `showanswer` statement.

    The server emits this statement when the answer to a problem is shown.

    Attributes:
        event (dict): See ShowAnswerEventField.
        event_type (str): Consists of the value `showanswer`.
        page (str): Consists of the value `x_module`.
    """

    __selector__ = selector(event_source="server", event_type="showanswer")

    event: ShowAnswerEventField
    event_type: Literal["showanswer"]
    page: Literal["x_module"]
