"""InterventionHandlerMixin — 用户干预处理（/stop /debate 纯文本）。

# TYPE_CHECKING: 由 TeamOrchestrator 组合，访问 self 共享状态
"""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING

from .expert import Expert
from .plan import TeamPlan

if TYPE_CHECKING:
    from .team import ExpertTeam

logger = logging.getLogger(__name__)


class InterventionHandlerMixin:
    """Mixin: 阶段边界处理用户干预（stop/debate/纯文本）。由 TeamOrchestrator 组合。"""

    # Shared state provided by TeamOrchestrator (annotations only)
    _team: ExpertTeam
    _debate_count: int
    _user_context: list[str]
    STOP_COMMANDS: frozenset[str]
    MAX_DEBATES: int

    def _consume_team_interventions(self) -> list[str]:
        """Consume user interventions from the team, if available.

        Checks ExpertTeam for an intervention queue (added in U4).
        Falls back to empty list if the team doesn't support interventions yet.
        """
        consume = getattr(self._team, "consume_user_interventions", None)
        if consume is None:
            return []
        try:
            return consume()
        except Exception:
            return []

    def _has_stop_command(self, interventions: list[str]) -> bool:
        """Check if any user intervention contains a stop command."""
        for msg in interventions:
            if msg.strip().lower() in self.STOP_COMMANDS:
                return True
        return False

    # ── U4: User intervention processing at phase boundaries ──────────

    async def _process_interventions(self, lead: Expert, plan: TeamPlan) -> bool:
        """Process pending user interventions at a phase boundary.

        Handles three intervention kinds:
        - ``/stop`` (or aliases) → returns True to signal termination
        - ``/debate <topic>`` → dynamically inserts a DEBATE phase
          (bounded by MAX_DEBATES); the debate depends on the most recently
          completed phase so it runs before remaining pending phases
        - plain text → accumulated in ``_user_context`` for Lead synthesis

        Returns:
            True if execution should stop, False to continue.
        """
        interventions = self._consume_team_interventions()
        if not interventions:
            return False

        for msg in interventions:
            stripped = msg.strip()
            if not stripped:
                continue
            lower = stripped.lower()

            # /stop → terminate
            if lower in self.STOP_COMMANDS:
                await self._broadcast_event(
                    "plan_update",
                    {
                        "plan_id": plan.id,
                        "plan_phases": [p.to_dict() for p in plan.phases],
                        "stopped_by_user": True,
                    },
                )
                return True

            # /debate <topic> → insert DEBATE phase
            if lower.startswith("/debate"):
                topic = stripped[len("/debate") :].strip()
                if not topic:
                    continue
                if self._debate_count >= self.MAX_DEBATES:
                    logger.info(
                        f"Max debates ({self.MAX_DEBATES}) reached, ignoring /debate intervention"
                    )
                    continue
                participants = [
                    e.config.name
                    for e in self._team.active_experts
                    if e.config.name != lead.config.name
                ]
                if not participants:
                    continue
                # Anchor the debate on the most recently completed phase
                # so it runs before remaining pending phases. If none
                # completed yet, the debate has no deps and runs immediately.
                anchor = plan.completed_phases[-1] if plan.completed_phases else None
                trigger = anchor or plan.phases[0]
                debate = self._insert_debate_phase(
                    plan, trigger, f"用户发起：{topic}", participants
                )
                if debate:
                    await self._broadcast_event(
                        "plan_update",
                        {
                            "plan_id": plan.id,
                            "plan_phases": [p.to_dict() for p in plan.phases],
                            "debate_inserted": debate.id,
                        },
                    )
                continue

            # Plain text → accumulate as user context
            self._user_context.append(stripped)

        return False
