"""Session models — Pydantic data structures for the Cursor Session Protocol.

Two directions:
  - Presentation: External agent (Cursor) presents TO the Vastian Network
  - Request: Vastian agents request something FROM the external agent (Cursor)
"""

from __future__ import annotations

import uuid
from datetime import UTC, datetime
from enum import StrEnum

from pydantic import BaseModel, Field


class SessionDirection(StrEnum):
    """Which way the conversation flows."""

    PRESENTATION = "presentation"  # External → Network (Cursor presents to agents)
    REQUEST = "request"  # Network → External (agents request from Cursor)


class SessionPhase(StrEnum):
    """Lifecycle phases of a session."""

    OPEN = "open"  # Active — accepting messages
    WRAPPING = "wrapping"  # Being summarized
    COMPLETED = "completed"  # Done, summary generated


class SessionMessage(BaseModel):
    """A single message in a session — from presenter, requester, or agent."""

    id: str = Field(default_factory=lambda: uuid.uuid4().hex[:8])
    sender: str  # "presenter" / agent_id
    sender_name: str  # Display name (e.g., "Cursor AI" or "Henry")
    content: str
    round_number: int = 0
    message_type: str = "broadcast"  # broadcast, targeted, discuss, wrap, request
    target_agent: str | None = None  # For targeted messages
    timestamp: datetime = Field(default_factory=lambda: datetime.now(UTC))


class SessionRound(BaseModel):
    """A collection of messages constituting one round of dialogue."""

    round_number: int
    initiator_message: SessionMessage | None = None  # From presenter or requesting agent
    responses: list[SessionMessage] = Field(default_factory=list)
    round_type: str = "broadcast"  # broadcast, targeted, discuss, request


class VastianSession(BaseModel):
    """
    A bidirectional session between external agents and the Vastian Network.

    Presentations: External agent presents to the network, agents respond.
    Requests: Network agent requests something from the external agent, external responds.

    Wave 6 additions:
      session_type  — one of the 9 session types from config/sessions.yaml (or None for legacy)
      display_name  — Noah-generated creative name for this session instance
      theme         — Noah-generated theme/flavor text
      lead_agent    — agent_id of the session lead (from session type config)
    """

    id: str = Field(default_factory=lambda: uuid.uuid4().hex[:12])
    direction: SessionDirection
    topic: str

    # Wave 6: session type fields
    session_type: str | None = None  # e.g. "daily_briefing", "recalibration"
    display_name: str | None = None  # Noah-generated creative session name
    theme: str | None = None  # Noah-generated theme/flavor
    lead_agent: str | None = None  # agent_id of the session lead

    # Presentation fields
    presenter_name: str = "Cursor AI"
    brief_path: str | None = None
    brief_content: str = ""

    # Request fields
    requesting_agent: str | None = None  # agent_id who initiated the request
    requesting_agent_name: str | None = None

    # Common fields
    phase: SessionPhase = SessionPhase.OPEN
    agent_ids: list[str] = Field(default_factory=list)
    rounds: list[SessionRound] = Field(default_factory=list)
    current_round: int = 0
    summary: str = ""
    action_items: list[dict] = Field(default_factory=list)
    human_feedback: list[dict] = Field(default_factory=list)  # {feedback, timestamp}
    round_analyses: list[dict] = Field(default_factory=list)  # Per-round sentiment analysis
    created_at: datetime = Field(default_factory=lambda: datetime.now(UTC))
    completed_at: datetime | None = None

    def add_round(
        self,
        initiator_msg: SessionMessage | None,
        responses: list[SessionMessage],
        round_type: str = "broadcast",
    ) -> SessionRound:
        """Record a complete round of dialogue."""
        self.current_round += 1
        session_round = SessionRound(
            round_number=self.current_round,
            initiator_message=initiator_msg,
            responses=responses,
            round_type=round_type,
        )
        self.rounds.append(session_round)
        return session_round

    @property
    def all_messages(self) -> list[SessionMessage]:
        """Flat list of all messages in chronological order."""
        msgs: list[SessionMessage] = []
        for r in self.rounds:
            if r.initiator_message:
                msgs.append(r.initiator_message)
            msgs.extend(r.responses)
        return msgs

    @property
    def direction_label(self) -> str:
        """Human-readable direction label."""
        if self.direction == SessionDirection.PRESENTATION:
            return "Presentation"
        return "Request"

    @property
    def transcript(self) -> str:
        """Generate a human-readable transcript of the session."""
        if self.direction == SessionDirection.PRESENTATION:
            title = f"Presentation — {self.topic}"
            header_line = f"**Presenter:** {self.presenter_name}"
        else:
            title = f"Request — {self.topic}"
            header_line = f"**Requested by:** {self.requesting_agent_name or self.requesting_agent}"

        lines = [
            f"# {title}",
            header_line,
            f"**Participants:** {', '.join(self.agent_ids)}",
            f"**Date:** {self.created_at.strftime('%Y-%m-%d %H:%M UTC')}",
            "",
        ]

        for r in self.rounds:
            lines.append(f"\n## Round {r.round_number} ({r.round_type})")
            lines.append("")

            if r.initiator_message:
                lines.append(f"### {r.initiator_message.sender_name}")
                lines.append(r.initiator_message.content)
                lines.append("")

            for resp in r.responses:
                lines.append(f"### {resp.sender_name}")
                lines.append(resp.content)
                lines.append("")

        if self.summary:
            lines.append("\n## Session Summary")
            lines.append(self.summary)

        if self.action_items:
            lines.append("\n## Action Items")
            for item in self.action_items:
                agent = item.get("assigned_to", "unassigned")
                desc = item.get("description", "")
                lines.append(f"- **{agent}**: {desc}")

        return "\n".join(lines)

    def to_summary(self) -> dict:
        """Generate a compact summary dict."""
        result = {
            "id": self.id,
            "direction": self.direction.value,
            "topic": self.topic,
            "phase": self.phase.value,
            "agents": self.agent_ids,
            "rounds": self.current_round,
            "total_messages": len(self.all_messages),
            "created_at": self.created_at.isoformat(),
            "completed_at": self.completed_at.isoformat() if self.completed_at else None,
            # Wave 6 fields
            "session_type": self.session_type,
            "display_name": self.display_name,
            "theme": self.theme,
            "lead_agent": self.lead_agent,
        }
        if self.direction == SessionDirection.PRESENTATION:
            result["presenter"] = self.presenter_name
        else:
            result["requested_by"] = self.requesting_agent_name or self.requesting_agent
        return result
