"""BoardTeam - 私董会讨论模式容器

管理私董会的专家生命周期、讨论状态和事件广播。
与 ExpertTeam（hub-and-spoke 任务分解）并列，专注于多轮群聊式讨论。

核心差异（vs ExpertTeam）：
- 讨论模式：多轮全员发言 + 主持人小结，非任务分解
- 专家通信：基于共享讨论历史，非独立子任务
- 终止机制：最大轮次 + 用户干预，非任务完成
- 主持人角色：首位专家，负责开场/小结/最终总结
"""

from __future__ import annotations

import enum
import logging
import time
import uuid

from .config import ExpertConfig
from .expert import Expert
from .registry import ExpertTemplateRegistry
from ..core.handoff_transport import InProcessHandoffTransport
from ..core.shared_workspace import SharedWorkspace
from ..core.agent_pool import AgentPool

logger = logging.getLogger(__name__)


class BoardStatus(str, enum.Enum):
    """BoardTeam lifecycle states.

    Flow: FORMING → DISCUSSING → CONCLUDING → COMPLETED → DISSOLVED
    """

    FORMING = "forming"
    DISCUSSING = "discussing"
    CONCLUDING = "concluding"
    COMPLETED = "completed"
    DISSOLVED = "dissolved"


class BoardTeam:
    """Container managing a board of Experts in discussion mode.

    In board meeting mode:
    - Moderator (lead expert) opens the discussion, summarizes each round,
      and gives final decision advice
    - Member experts give speeches each round based on shared discussion history
    - All experts see the full discussion history (shared context)
    - Discussion terminates after max_rounds or user intervention
    """

    def __init__(
        self,
        team_id: str | None = None,
        workspace: SharedWorkspace | None = None,
        pool: AgentPool | None = None,
        template_registry: ExpertTemplateRegistry | None = None,
        max_rounds: int = 5,
    ):
        self.team_id = team_id or str(uuid.uuid4())
        self._workspace = workspace or SharedWorkspace()
        self._pool = pool
        self._template_registry = template_registry or ExpertTemplateRegistry()
        self._handoff_transport = InProcessHandoffTransport()
        self._experts: dict[str, Expert] = {}
        self._moderator_name: str | None = None
        self._status = BoardStatus.FORMING
        self._team_channel = f"board:{self.team_id}"

        # Discussion state
        self._topic: str = ""
        self._history: list[dict[str, object]] = []
        self._current_round: int = 0
        self._max_rounds: int = max_rounds
        self._user_interventions: list[str] = []  # Pending user messages

    @property
    def status(self) -> BoardStatus:
        return self._status

    @property
    def moderator(self) -> Expert | None:
        if self._moderator_name:
            return self._experts.get(self._moderator_name)
        return None

    @property
    def experts(self) -> list[Expert]:
        return list(self._experts.values())

    @property
    def active_experts(self) -> list[Expert]:
        return [e for e in self._experts.values() if e.is_active]

    @property
    def member_experts(self) -> list[Expert]:
        """Non-moderator experts."""
        return [e for e in self._experts.values() if e.config.name != self._moderator_name]

    @property
    def workspace(self) -> SharedWorkspace:
        return self._workspace

    @property
    def handoff_transport(self):
        return self._handoff_transport

    @property
    def team_channel(self) -> str:
        return self._team_channel

    @property
    def topic(self) -> str:
        return self._topic

    @property
    def current_round(self) -> int:
        return self._current_round

    @property
    def max_rounds(self) -> int:
        return self._max_rounds

    @property
    def history(self) -> list[dict[str, object]]:
        return self._history.copy()

    def get_expert(self, name: str) -> Expert | None:
        return self._experts.get(name)

    def set_status(self, status: BoardStatus) -> None:
        self._status = status

    async def create_board(
        self,
        topic: str,
        expert_configs: list[ExpertConfig],
    ) -> None:
        """Create a board with a moderator and member experts.

        Args:
            topic: Discussion topic
            expert_configs: List of ExpertConfig, first is moderator
        """
        if not self._pool:
            raise RuntimeError("AgentPool not configured")

        if not expert_configs:
            raise ValueError("At least one expert config is required")

        self._topic = topic

        # Build board context for all experts
        board_context = self._build_board_context(expert_configs)

        # Create experts
        for i, config in enumerate(expert_configs):
            expert = await Expert.create(
                config=config,
                pool=self._pool,
                handoff_transport=self._handoff_transport,
                workspace=self._workspace,
                team_context=board_context,
            )
            expert.team_id = self.team_id
            self._experts[config.name] = expert

            # First expert is moderator
            if i == 0:
                self._moderator_name = config.name

        self._status = BoardStatus.DISCUSSING

    def _build_board_context(self, expert_configs: list[ExpertConfig]) -> str:
        """Build board context string for injection into Expert system prompts.

        Emphasizes discussion mode, role differentiation, and discussion rules.
        """
        lines = ["You are part of a Board Meeting (private board discussion mode)."]

        for i, config in enumerate(expert_configs):
            role = "Moderator" if i == 0 else "Member"
            lines.append(
                f"{role}: {config.name} ({config.persona[:100]}...)"
                f" — Thinking: {config.thinking_style}"
                f" — Speaking: {config.speaking_style}"
                f" — Framework: {config.decision_framework}"
            )

        lines.append("")
        lines.append("Board meeting rules:")
        lines.append("- Each round, all members give speeches based on their persona and framework")
        lines.append("- Moderator opens the discussion, summarizes each round, and gives final advice")
        lines.append("- All experts see the full discussion history (shared context)")
        lines.append("- Stay in character: think and speak as your persona would")
        lines.append("- Be concise but insightful: 2-4 paragraphs per speech")
        lines.append("- Build on or respectfully challenge previous speakers' points")
        return "\n".join(lines)

    async def add_to_history(
        self,
        round: int,
        expert_name: str,
        content: str,
        role: str = "expert",
    ) -> None:
        """Add a speech to the discussion history.

        Args:
            round: Round number (1-indexed)
            expert_name: Name of the expert (or "user" for interventions)
            content: Speech content
            role: "expert" | "moderator" | "user"
        """
        entry = {
            "round": round,
            "expert_name": expert_name,
            "content": content,
            "timestamp": time.time(),
            "role": role,
        }
        self._history.append(entry)

    def get_history_text(self, up_to_round: int | None = None) -> str:
        """Get formatted discussion history for LLM prompt injection.

        Args:
            up_to_round: If provided, only include history up to this round (inclusive)

        Returns:
            Formatted history text
        """
        if not self._history:
            return ""

        lines: list[str] = []
        for entry in self._history:
            if up_to_round is not None and entry["round"] > up_to_round:
                continue

            role_label = {
                "moderator": "主持人小结",
                "user": "用户干预",
                "expert": "专家发言",
            }.get(entry["role"], entry["role"])

            lines.append(
                f"[第{entry['round']}轮 | {entry['expert_name']} | {role_label}]\n"
                f"{entry['content']}"
            )

        return "\n\n---\n\n".join(lines)

    async def compress_history(self, moderator: Expert, llm_gateway: object) -> None:
        """Compress discussion history when it exceeds token threshold.

        The moderator summarizes each round's key points, replacing
        verbose speeches with concise summaries.

        Args:
            moderator: Moderator expert
            llm_gateway: LLM gateway for compression
        """
        if not self._history or len(self._history) < 10:
            return

        # Group by round
        rounds: dict[int, list[dict]] = {}
        for entry in self._history:
            rounds.setdefault(entry["round"], []).append(entry)

        # Build compression prompt
        history_text = self.get_history_text()
        prompt = (
            "你是私董会主持人。请压缩以下讨论历史，保留每轮的关键观点和核心论点，"
            "去除冗余内容。每轮压缩为 2-3 句话。\n\n"
            f"讨论历史:\n{history_text}\n\n"
            "请输出压缩后的历史，保持原有的轮次结构和专家名。格式:\n"
            "[第X轮 | 专家名] 压缩后的观点"
        )

        try:
            response = await llm_gateway.chat(
                messages=[{"role": "user", "content": prompt}],
                model="default",
            )
            compressed = response.content.strip()

            # Parse compressed history back to entries
            # This is a best-effort compression; if parsing fails, keep original
            new_history: list[dict[str, object]] = []
            current_round = 0
            for line in compressed.split("\n"):
                line = line.strip()
                if not line:
                    continue
                if line.startswith("[第") and "轮" in line:
                    # Parse round number
                    try:
                        round_str = line.split("第")[1].split("轮")[0]
                        current_round = int(round_str)
                        name_part = line.split("|")[1].strip() if "|" in line else "unknown"
                        content_part = line.split("]", 1)[1].strip() if "]" in line else line
                        new_history.append({
                            "round": current_round,
                            "expert_name": name_part,
                            "content": content_part,
                            "timestamp": time.time(),
                            "role": "expert",
                        })
                    except (ValueError, IndexError):
                        continue

            if new_history:
                self._history = new_history
                logger.info(f"History compressed: {len(rounds)} rounds, {len(new_history)} entries")
        except Exception as e:
            logger.warning(f"History compression failed: {e}, keeping original history")

    async def add_user_intervention(self, content: str) -> None:
        """Add a user intervention message to the discussion.

        The message will be visible to all experts in the next round.

        Args:
            content: User's intervention message
        """
        self._user_interventions.append(content)
        await self.add_to_history(
            round=self._current_round,
            expert_name="user",
            content=content,
            role="user",
        )

        # Broadcast user intervention event
        await self._handoff_transport.send(
            self._team_channel,
            {
                "type": "user_intervention",
                "content": content,
                "round": self._current_round,
            },
        )

    def consume_user_interventions(self) -> list[str]:
        """Get and clear pending user interventions.

        Returns:
            List of user intervention messages
        """
        interventions = self._user_interventions.copy()
        self._user_interventions.clear()
        return interventions

    def increment_round(self) -> int:
        """Increment the current round counter.

        Returns:
            The new round number
        """
        self._current_round += 1
        return self._current_round

    async def dissolve(self) -> None:
        """Dissolve the board. Experts are recycled, outputs preserved."""
        for expert in self._experts.values():
            if expert.is_active and self._pool:
                await expert.destroy(self._pool)

        self._experts.clear()
        self._moderator_name = None
        self._status = BoardStatus.DISSOLVED
        self._handoff_transport.close()
