from dataclasses import dataclass
from typing import ClassVar

from engine.events.agents import AgentReported
from controllers.types import Agents, Questions
from engine.events.resources import AnyEvent, MessageCreated, QuestionAnswered, ResourceEvent
from engine.sessions import Sessions
from features.agent_sessions.launch import driver_in
from features.sending import Sent
from features.triggers import watched
from features.trigger import DAY, MINUTE
from providers.turns import last_text
from features.parts import AgentContext, Context, Handler
from features.ask_questions.choices import offers_choices
from resources.base import SYSTEM, USER, Ref

ASKING = "asking"
WAITED_ON = ("todo", "plan", "ticket")
GONE = {"completed": "closed", "deleted": "deleted"}


@dataclass(frozen=True)
class QuestionAsked(ResourceEvent):
    on: ClassVar[str] = "question.created"


class AskInsteadOfProse(Handler):
    behaviour = ASKING

    def handle(self, context: AgentContext, event: AgentReported) -> None:
        if offers_choices(last_text(context.agent.row)):
            context.agent.say("prose")
            context.hold("prose held", ASKING)


class ReleaseOnceAnswered(Handler):
    def handle(self, context: Context, event: MessageCreated) -> None:
        if event.actor == USER:
            context.release(ASKING)


class ReleaseOnceAsked(Handler):
    def handle(self, context: Context, event: QuestionAsked) -> None:
        context.release(ASKING)


class MarkTheAnswer(Handler):
    def handle(self, context: Context, event: QuestionAnswered) -> None:
        question = Questions(context.record, actor=SYSTEM).load(event.n)
        agents = Agents(context.record, actor=SYSTEM)
        row = agents.primary()
        if event.actor != USER or question.hidden or not row or Sessions(context.record.root).asking(question.n):
            return
        agents.card(row.n, label=f"You answered question {question.n}", icon="question",
                    color="var(--blocking)", side=USER, row=question.ref)
        context.feature.to_primary(context.record, "answered", n=question.n, answer=question.outcome, rows=[question.ref])


class AnswerOnTheScreen(Handler):
    def handle(self, context: Context, event: QuestionAnswered) -> None:
        """An answer reaches the question the agent stands at on its own screen, which no typed line can: the option is pressed, or the words are typed into the free choice."""
        question = Questions(context.record, actor=SYSTEM).load(event.n)
        row = Agents(context.record, actor=SYSTEM).primary()
        driver = driver_in(context.record, context.record.env, row.provider) if row else None
        if driver is not None and question.completed and not Sessions(context.record.root).asking(question.n):
            driver.answer_prompt(int(question.chosen), question.outcome, len(question.options))


class DismissSettledQuestions(Handler):
    def handle(self, context: Context, event: AnyEvent) -> None:
        if event.type not in WAITED_ON or event.action not in GONE:
            return
        ref, questions = Ref(event.type, event.n), Questions(context.record, actor=SYSTEM)
        for question in [q for q in questions.rows.standing() if str(ref) in q.refs]:
            questions.dismiss(question.n, why=f"{ref.spoken}, which it was about, is {GONE[event.action]}")


def open_a_day(context, agent) -> list[Sent]:
    return watched.found("question.open", context, agent, DAY / MINUTE)
