from __future__ import annotations

from dataclasses import dataclass, field
from datetime import datetime
from pathlib import Path
from typing import Literal
import json

ROLE_DIR = Path("/root/projects/meeting/agents")


@dataclass
class AgentConfig:
    name: str
    role: str
    system_prompt: str
    input_schema: str = ""
    output_schema: str = ""


@dataclass
class ScratchpadEntry:
    agent_name: str
    content: str
    timestamp: datetime = field(default_factory=datetime.now)


@dataclass
class MeetingState:
    topic: str
    context: str = ""
    scratchpad: list[ScratchpadEntry] = field(default_factory=list)
    current_round: int = 0
    max_rounds: int = 10


@dataclass
class PMDecision:
    analysis: str
    next_action: Literal["CALL_AGENT", "FINISH"]
    target_agent: str | None = None
    prompt_for_agent: str | None = None
    final_report: str | None = None


@dataclass
class MeetingPlan:
    topic: str
    roles: list[str]
    context: str = ""
    max_rounds: int = 10
    human_in_the_loop: bool = True


@dataclass
class MeetingRunResult:
    report: str
    transcript: list[ScratchpadEntry]
    participants: list[str]
    started_at: datetime
    finished_at: datetime


def load_role_config(role_name: str) -> AgentConfig:
    path = ROLE_DIR / f"{role_name}.json"
    data = json.loads(path.read_text(encoding="utf-8"))
    return AgentConfig(
        name=data["name"],
        role=data["role"],
        system_prompt=data["system_prompt"],
        input_schema=data.get("input_schema", ""),
        output_schema=data.get("output_schema", ""),
    )


def load_role_names() -> list[str]:
    return sorted(p.stem for p in ROLE_DIR.glob("*.json"))


def build_meeting_plan(topic: str, roles: list[str], context: str = "", max_rounds: int = 10) -> MeetingPlan:
    return MeetingPlan(topic=topic, roles=roles, context=context, max_rounds=max_rounds)


def format_scratchpad(entries: list[ScratchpadEntry]) -> str:
    if not entries:
        return "No discussion yet."
    return "\n".join(f"[{e.agent_name}]: {e.content}" for e in entries)


def build_pm_prompt(plan: MeetingPlan, state: MeetingState, participants: dict[str, AgentConfig]) -> str:
    role_list = "\n".join(f"- {name}: {cfg.role}" for name, cfg in participants.items())
    scratchpad = format_scratchpad(state.scratchpad)
    return (
        f"## Topic\n\n{plan.topic}\n\n"
        f"## Background Context\n\n{plan.context or 'None'}\n\n"
        f"## Participants\n\n{role_list}\n\n"
        f"## Current Whiteboard (Round {state.current_round})\n\n{scratchpad}"
    )


def build_agent_prompt(topic: str, context: str, scratchpad: str, task: str) -> str:
    sections = [
        f"## Topic\n\n{topic}",
    ]
    if context:
        sections.append(f"## Context\n\n{context}")
    sections.append(f"## Current Meeting Whiteboard\n\n{scratchpad}")
    sections.append(f"## Your Task\n\n{task}")
    return "\n\n".join(sections)


def build_single_role_prompt(role_name: str, topic: str, context: str = "") -> tuple[AgentConfig, str]:
    role = load_role_config(role_name)
    scratchpad = "No discussion yet."
    task = "Evaluate the topic directly. Give a clear judgment, risks, and the next best move."
    return role, build_agent_prompt(topic=topic, context=context, scratchpad=scratchpad, task=task)


def run_meeting_native(
    plan: MeetingPlan,
    client,
    select_participants,
    route_pm,
    run_role,
    interrupt_hook=None,
) -> MeetingRunResult:
    started_at = datetime.now()
    state = MeetingState(topic=plan.topic, context=plan.context, max_rounds=plan.max_rounds)
    participants = {name: load_role_config(name) for name in select_participants(plan)}
    final_report = ""

    while state.current_round < state.max_rounds:
        state.current_round += 1
        decision = route_pm(plan, state, participants, client)
        if decision.next_action == "FINISH":
            final_report = decision.final_report or "# Meeting Report\n\nNo report generated."
            break

        if decision.target_agent not in participants:
            raise ValueError(f"PM selected unavailable agent: {decision.target_agent}")

        scratchpad_text = format_scratchpad(state.scratchpad)
        agent_prompt = build_agent_prompt(
            topic=plan.topic,
            context=plan.context,
            scratchpad=scratchpad_text,
            task=decision.prompt_for_agent or "Respond with your judgment.",
        )
        response = run_role(participants[decision.target_agent], agent_prompt, client)
        state.scratchpad.append(ScratchpadEntry(agent_name=decision.target_agent, content=response))

        if interrupt_hook is not None:
            interrupt_hook(plan=plan, state=state, latest_agent=decision.target_agent, latest_response=response)

    if not final_report:
        final_report = "# Meeting Report\n\nMeeting ended after maximum rounds without PM conclusion."

    return MeetingRunResult(
        report=final_report,
        transcript=list(state.scratchpad),
        participants=list(participants.keys()),
        started_at=started_at,
        finished_at=datetime.now(),
    )
