"""
Director Agent Tools
用于 Agent-Native 协作模式的工具集

结合 skills-agent-proto 的设计模式，使用 ToolRuntime 访问运行时状态
"""
from langchain.tools import tool, ToolRuntime
from .context import SkillAgentContext
from typing import List, Optional, Dict, Any
import json

# Director 专用的状态键
PLAN_STATE_KEY = "director_plan"
INBOX_STATE_KEY = "director_inbox"
ANNOTATION_STATE_KEY = "director_annotations"
CONTEXT_STATE_KEY = "director_context"


@tool
def update_plan(
    steps: List[str],
    current_step_index: int = 0,
    status: str = 'planning',
    runtime: ToolRuntime[SkillAgentContext] = None
) -> str:
    """
    Update the current execution plan displayed to the user.

    This tool updates the director's plan which will be sent to the frontend
    via WebSocket events. The plan shows the user what steps the agent is
    working on and the current progress.

    Args:
        steps: List of plan steps (e.g. ["Analyze context", "Create outline", "Write draft"])
        current_step_index: Index of the current step (0-based)
        status: Current status ('planning', 'writing', 'reviewing', 'idle')

    Returns:
        Confirmation message with plan details

    Example:
        update_plan(steps=["Research", "Outline", "Write"], current_step_index=0, status="planning")
    """
    if runtime is None:
        return "Error: runtime context not available"

    # 存储计划状态到 runtime.state
    plan_data = {
        "steps": steps,
        "current_step_index": current_step_index,
        "status": status
    }
    runtime.state[PLAN_STATE_KEY] = plan_data

    step_info = ""
    if steps and current_step_index < len(steps):
        current_step = steps[current_step_index]
        step_info = f"Current: [{current_step_index + 1}/{len(steps)}] {current_step}"

    return f"""✓ Plan updated with {len(steps)} steps
Status: {status}
{step_info}

Steps:
{chr(10).join(f'{i+1}. {step}' for i, step in enumerate(steps))}"""


@tool
def add_inbox_task(
    title: str,
    description: str,
    task_type: str = 'review',
    options: Optional[List[str]] = None,
    runtime: ToolRuntime[SkillAgentContext] = None
) -> str:
    """
    Add a task to the Director's Inbox for human review/decision.

    This tool creates a task that will appear in the user's inbox, allowing
    for human-in-the-loop collaboration. The user can approve, reject, or
    provide feedback on the task.

    Args:
        title: Short title of the task (e.g. "Review Episode 1 Outline")
        description: Detailed description or question for the user
        task_type: Type of task ('review', 'decision', 'notification')
        options: List of available options for decision (e.g. ["Approve", "Reject"])

    Returns:
        Confirmation message with task details

    Example:
        add_inbox_task(
            title="Review Character Arc",
            description="Does this character development make sense?",
            task_type="review",
            options=["Approve", "Request Changes"]
        )
    """
    if runtime is None:
        return "Error: runtime context not available"

    # 确保 inbox 列表存在
    if INBOX_STATE_KEY not in runtime.state:
        runtime.state[INBOX_STATE_KEY] = []

    # 创建任务
    task = {
        "id": f"task_{len(runtime.state[INBOX_STATE_KEY])}_{hash(title) % 10000}",
        "title": title,
        "description": description,
        "type": task_type,
        "options": options or ["Approve", "Reject"],
        "timestamp": None  # Will be set by WebSocket handler
    }

    # 添加到 inbox
    runtime.state[INBOX_STATE_KEY].append(task)

    return f"""✓ Task added to Director's Inbox

Title: {title}
Type: {task_type}
Description: {description[:100]}{'...' if len(description) > 100 else ''}

Waiting for director's response..."""


@tool
def add_annotation(
    content: str,
    annotation_type: str = 'review',
    suggestion: str = '',
    runtime: ToolRuntime[SkillAgentContext] = None
) -> str:
    """
    Add an annotation/comment to the canvas for the user to see.

    This tool creates annotations that appear on the content canvas,
    highlighting issues or providing feedback without interrupting
    the agent's workflow.

    Args:
        content: The text content being annotated or description of issue
        annotation_type: Type of annotation ('consistency', 'grammar', 'style', 'plot', 'review')
        suggestion: Suggested fix or improvement

    Returns:
        Confirmation message with annotation details

    Example:
        add_annotation(
            content="Character name changed from 'John' to 'Jon'",
            annotation_type="consistency",
            suggestion="Use consistent spelling throughout"
        )
    """
    if runtime is None:
        return "Error: runtime context not available"

    # 确保 annotations 列表存在
    if ANNOTATION_STATE_KEY not in runtime.state:
        runtime.state[ANNOTATION_STATE_KEY] = []

    # 创建批注
    annotation = {
        "content": content,
        "type": annotation_type,
        "suggestion": suggestion,
        "timestamp": None  # Will be set by WebSocket handler
    }

    # 添加到列表
    runtime.state[ANNOTATION_STATE_KEY].append(annotation)

    return f"""✓ Annotation added to canvas

Type: {annotation_type}
Content: {content[:100]}{'...' if len(content) > 100 else ''}
{suggestion and f"Suggestion: {suggestion}" or ""}"""


@tool
def update_context(
    context_type: str,
    data: Any = None,
    runtime: ToolRuntime[SkillAgentContext] = None
) -> str:
    """
    Update the dynamic context panel (e.g. world state, character status).

    This tool updates the context panel shown in the left sidebar, keeping
    the user informed of the current story state, character conditions,
    and other dynamic information.

    Args:
        context_type: Type of context to update ('world', 'character', 'state', 'all')
        data: Data to update (can be string, dict, or list of state objects)

    Returns:
        Confirmation message with context details

    Example:
        update_context(
            context_type="state",
            data=[{"type": "location", "value": "Throne Room"}, {"type": "time", "value": "Evening"}]
        )
    """
    if runtime is None:
        return "Error: runtime context not available"

    # 处理不同类型的数据输入
    if isinstance(data, str):
        try:
            data = json.loads(data)
        except json.JSONDecodeError:
            # 如果不是 JSON，当作简单的键值对
            data = [{"type": context_type, "value": data}]

    # 确保 context 状态存在
    if CONTEXT_STATE_KEY not in runtime.state:
        runtime.state[CONTEXT_STATE_KEY] = {}

    # 更新上下文
    if context_type == 'all' and isinstance(data, list):
        # 更新所有状态
        runtime.state[CONTEXT_STATE_KEY] = {item['type']: item['value'] for item in data}
    elif isinstance(data, list):
        # 更新特定类型的状态
        for item in data:
            if isinstance(item, dict) and 'type' in item and 'value' in item:
                runtime.state[CONTEXT_STATE_KEY][item['type']] = item['value']
    elif isinstance(data, dict):
        # 直接更新字典
        runtime.state[CONTEXT_STATE_KEY].update(data)

    # 生成状态摘要
    states = runtime.state[CONTEXT_STATE_KEY]
    state_summary = '\n'.join(f'  • {k}: {v}' for k, v in states.items())

    return f"""✓ Context updated

Type: {context_type}
Current states:
{state_summary}"""


@tool
def write_to_canvas(
    content: str,
    append: bool = True,
    runtime: ToolRuntime[SkillAgentContext] = None
) -> str:
    """
    Write content directly to the canvas (main content area).

    This tool updates the main content canvas with new text. It can either
    append to existing content or replace it entirely.

    Args:
        content: The text content to write to the canvas
        append: If True, append to existing content; if False, replace entirely

    Returns:
        Confirmation with content length info

    Example:
        write_to_canvas(content="# Episode 1\\n\\nOnce upon a time...", append=False)
    """
    if runtime is None:
        return "Error: runtime context not available"

    # 获取当前内容
    current_content = runtime.state.get("canvas_content", "")

    if append:
        new_content = current_content + content
    else:
        new_content = content

    # 更新状态
    runtime.state["canvas_content"] = new_content

    lines = len(content.split('\n'))
    action = "appended to" if append else "written to"
    return f"✓ Content {action} canvas ({lines} lines, {len(content)} characters)"


@tool
def save_episode(
    episode_number: int,
    title: str,
    content: str,
    outline: Optional[str] = None,
    runtime: ToolRuntime[SkillAgentContext] = None
) -> str:
    """
    Save episode content to the database.

    This tool saves the episode content to the project database,
    storing the outline, full content, and metadata.

    Args:
        episode_number: Episode number (e.g., 1, 2, 3...)
        title: Episode title
        content: Full episode script/content
        outline: Episode outline (optional)

    Returns:
        Confirmation message with episode details

    Example:
        save_episode(
            episode_number=1,
            title="The Beginning",
            content="Once upon a time...",
            outline="Introduction to the main characters"
        )
    """
    if runtime is None:
        return "Error: runtime context not available"

    # 获取项目 ID
    project_id = runtime.context.project_id if runtime.context else None
    if not project_id:
        return "Error: No project ID in context"

    # 存储到运行时状态（由 WebSocket 处理器保存到数据库）
    if "episodes_to_save" not in runtime.state:
        runtime.state["episodes_to_save"] = []

    episode_data = {
        "number": episode_number,
        "title": title,
        "content": content,
        "outline": outline,
        "status": "completed"
    }
    runtime.state["episodes_to_save"].append(episode_data)

    return f"""✓ Episode {episode_number} saved

Title: {title}
Content length: {len(content)} characters
{f"Outline: {outline[:50]}..." if outline else ""}

The episode has been queued for saving to the database."""


@tool
def update_memory(
    memory_type: str,
    data: Any,
    runtime: ToolRuntime[SkillAgentContext] = None
) -> str:
    """
    Update the story memory system.

    This tool updates various aspects of the story memory including
    timeline events, character states, pending threads, and foreshadowing.

    Args:
        memory_type: Type of memory to update ('timeline', 'character_state', 'pending_thread', 'foreshadowing')
        data: Data to update (format depends on memory_type)

    Returns:
        Confirmation message with memory details

    Example:
        update_memory(
            memory_type="character_state",
            data={"character": "Alice", "state": "injured", "description": "Leg injury from fall"}
        )
    """
    if runtime is None:
        return "Error: runtime context not available"

    # 存储到运行时状态（由 WebSocket 处理器保存到数据库）
    if "memory_updates" not in runtime.state:
        runtime.state["memory_updates"] = []

    memory_update = {
        "type": memory_type,
        "data": data
    }
    runtime.state["memory_updates"].append(memory_update)

    # 格式化输出
    if memory_type == "timeline":
        return f"✓ Timeline event added: {data.get('event', 'Unknown event')}"
    elif memory_type == "character_state":
        return f"✓ Character state updated: {data.get('character', 'Unknown')} - {data.get('state', 'Unknown state')}"
    elif memory_type == "pending_thread":
        return f"✓ Pending thread added: {data.get('description', 'Unknown thread')}"
    elif memory_type == "foreshadowing":
        return f"✓ Foreshadowing added: {data.get('description', 'Unknown foreshadowing')}"
    else:
        return f"✓ Memory updated: {memory_type}"


@tool
def request_review(
    content: str,
    review_type: str = 'quality',
    criteria: Optional[List[str]] = None,
    runtime: ToolRuntime[SkillAgentContext] = None
) -> str:
    """
    Request a content review from the Director.

    This tool creates a review request that will be sent to the Director
    for approval. It can be used for quality checks, consistency reviews,
    or other types of content validation.

    Args:
        content: The content to review (or description of what to review)
        review_type: Type of review ('quality', 'consistency', 'grammar', 'plot')
        criteria: Specific criteria to check (optional)

    Returns:
        Confirmation message with review request details

    Example:
        request_review(
            content="Episode 1 dialogue between Alice and Bob",
            review_type="quality",
            criteria=["Character voice consistency", "Dialogue naturalness"]
        )
    """
    if runtime is None:
        return "Error: runtime context not available"

    # 确保 inbox 列表存在
    if INBOX_STATE_KEY not in runtime.state:
        runtime.state[INBOX_STATE_KEY] = []

    # 创建审核任务
    task = {
        "id": f"review_{len(runtime.state[INBOX_STATE_KEY])}_{hash(content) % 10000}",
        "title": f"{review_type.capitalize()} Review Required",
        "description": f"Please review the following content:\n\n{content[:500]}{'...' if len(content) > 500 else ''}",
        "type": "review",
        "review_type": review_type,
        "criteria": criteria or [],
        "options": ["Approve", "Request Changes", "Skip"],
        "timestamp": None
    }

    # 添加到 inbox
    runtime.state[INBOX_STATE_KEY].append(task)

    criteria_text = "\n".join(f"  • {c}" for c in (criteria or []))
    criteria_section = ""
    if criteria_text:
        criteria_section = f"Criteria:\n{criteria_text}\n"

    return f"""✓ Review request created

Type: {review_type}
Content: {content[:100]}{'...' if len(content) > 100 else ''}
{criteria_section}
Waiting for director's review..."""


# 导出工具列表
DIRECTOR_TOOLS = [
    update_plan,
    add_inbox_task,
    add_annotation,
    update_context,
    write_to_canvas,
    save_episode,
    update_memory,
    request_review
]
