"""
Agent tools for trigger system.

Allows agents to:
- Schedule recurring tasks (cron-style)
- Execute one-time triggers
- Manage scheduled triggers (list, cancel)
- Connect events to sub-agent runs or lambdas
"""

import logging
from typing import Any, Dict, List, Optional

from langchain_core.tools import tool

logger = logging.getLogger(__name__)

# Global references set by main.py
_trigger_queue = None
_trigger_scheduler = None
_coordinator = None


def set_trigger_queue(queue):
    """Set the global TriggerQueue instance for tools to use."""
    global _trigger_queue
    _trigger_queue = queue


def set_trigger_scheduler(scheduler):
    """Set the global TriggerScheduler instance for tools to use."""
    global _trigger_scheduler
    _trigger_scheduler = scheduler


def set_coordinator(coordinator):
    """Set the global CommitCoordinator instance for tools to use."""
    global _coordinator
    _coordinator = coordinator


def _get_trigger_queue():
    """Get the global trigger queue instance."""
    if not _trigger_queue:
        raise ValueError("TriggerQueue not initialized")
    return _trigger_queue


def _get_trigger_scheduler():
    """Get the global trigger scheduler instance."""
    if not _trigger_scheduler:
        raise ValueError("TriggerScheduler not initialized")
    return _trigger_scheduler


def _get_coordinator():
    """Get the global coordinator instance."""
    if not _coordinator:
        raise ValueError("CommitCoordinator not initialized")
    return _coordinator


@tool
async def schedule_agent_prompt(
    prompt: str,
    schedule_type: str,
    schedule_config: Dict[str, Any],
    name: Optional[str] = None,
) -> Dict[str, str]:
    """Schedule an agent to run with a specific prompt on a recurring schedule.

    This allows you to set up automated tasks where the agent runs periodically
    with a predefined prompt. Useful for:
    - Daily market analysis reports
    - Hourly portfolio rebalancing checks
    - Weekly performance summaries
    - Monitoring alerts

    Args:
        prompt: The prompt to send to the agent when triggered
        schedule_type: Type of schedule - "interval" or "cron"
        schedule_config: Schedule configuration:
            For "interval": {"minutes": 5} or {"hours": 1, "minutes": 30}
            For "cron": {"hour": "9", "minute": "0"} for 9:00 AM daily
                       {"hour": "9", "minute": "0", "day_of_week": "mon-fri"}
        name: Optional descriptive name for this scheduled task

    Returns:
        Dictionary with job_id and confirmation message

    Examples:
        # Run every 5 minutes
        schedule_agent_prompt(
            prompt="Check BTC price and alert if > $50k",
            schedule_type="interval",
            schedule_config={"minutes": 5}
        )

        # Run daily at 9 AM
        schedule_agent_prompt(
            prompt="Generate daily market summary",
            schedule_type="cron",
            schedule_config={"hour": "9", "minute": "0"}
        )

        # Run hourly on weekdays
        schedule_agent_prompt(
            prompt="Monitor portfolio for rebalancing opportunities",
            schedule_type="cron",
            schedule_config={"minute": "0", "day_of_week": "mon-fri"}
        )
    """
    from trigger.handlers import LambdaHandler
    from trigger import Priority

    scheduler = _get_trigger_scheduler()
    queue = _get_trigger_queue()

    if not name:
        name = f"agent_prompt_{hash(prompt) % 10000}"

    # Create a lambda that enqueues an agent trigger with the prompt
    async def agent_prompt_lambda():
        from trigger.handlers import AgentTriggerHandler

        # Create agent trigger (will use current session's context)
        # In production, you'd want to specify which session/user this belongs to
        trigger = AgentTriggerHandler(
            session_id="scheduled",  # Special session for scheduled tasks
            message_content=prompt,
            coordinator=_get_coordinator(),
        )

        await queue.enqueue(trigger)
        return []  # No direct commit intents

    # Wrap in lambda handler
    lambda_trigger = LambdaHandler(
        name=f"scheduled_{name}",
        func=agent_prompt_lambda,
        priority=Priority.TIMER,
    )

    # Schedule based on type
    if schedule_type == "interval":
        job_id = scheduler.schedule_interval(
            lambda_trigger,
            seconds=schedule_config.get("seconds"),
            minutes=schedule_config.get("minutes"),
            hours=schedule_config.get("hours"),
            priority=Priority.TIMER,
        )
    elif schedule_type == "cron":
        job_id = scheduler.schedule_cron(
            lambda_trigger,
            minute=schedule_config.get("minute"),
            hour=schedule_config.get("hour"),
            day=schedule_config.get("day"),
            month=schedule_config.get("month"),
            day_of_week=schedule_config.get("day_of_week"),
            priority=Priority.TIMER,
        )
    else:
        raise ValueError(f"Invalid schedule_type: {schedule_type}. Use 'interval' or 'cron'")

    return {
        "job_id": job_id,
        "message": f"Scheduled '{name}' with job_id={job_id}",
        "schedule_type": schedule_type,
        "config": schedule_config,
    }


@tool
async def execute_agent_prompt_once(
    prompt: str,
    priority: str = "normal",
) -> Dict[str, str]:
    """Execute an agent prompt once, immediately (enqueued with priority).

    Use this to trigger a sub-agent with a specific task without waiting for
    a user message. Useful for:
    - Background analysis tasks
    - One-time data processing
    - Responding to specific events

    Args:
        prompt: The prompt to send to the agent
        priority: Priority level - "high", "normal", or "low"

    Returns:
        Confirmation that the prompt was enqueued

    Example:
        execute_agent_prompt_once(
            prompt="Analyze the last 100 BTC/USDT bars and identify support levels",
            priority="high"
        )
    """
    from trigger.handlers import AgentTriggerHandler
    from trigger import Priority

    queue = _get_trigger_queue()

    # Map string priority to enum
    priority_map = {
        "high": Priority.USER_AGENT,  # Same priority as user messages
        "normal": Priority.SYSTEM,
        "low": Priority.LOW,
    }
    priority_enum = priority_map.get(priority.lower(), Priority.SYSTEM)

    # Create agent trigger
    trigger = AgentTriggerHandler(
        session_id="oneshot",
        message_content=prompt,
        coordinator=_get_coordinator(),
    )

    # Enqueue with priority override
    queue_seq = await queue.enqueue(trigger, priority_enum)

    return {
        "queue_seq": queue_seq,
        "message": f"Enqueued agent prompt with priority={priority}",
        "prompt": prompt[:100] + "..." if len(prompt) > 100 else prompt,
    }


@tool
def list_scheduled_triggers() -> List[Dict[str, Any]]:
    """List all currently scheduled triggers.

    Returns:
        List of dictionaries with job information (id, name, next_run_time)

    Example:
        jobs = list_scheduled_triggers()
        for job in jobs:
            print(f"{job['id']}: {job['name']} - next run at {job['next_run_time']}")
    """
    scheduler = _get_trigger_scheduler()
    jobs = scheduler.get_jobs()

    result = []
    for job in jobs:
        result.append({
            "id": job.id,
            "name": job.name,
            "next_run_time": str(job.next_run_time) if job.next_run_time else None,
            "trigger": str(job.trigger),
        })

    return result


@tool
def cancel_scheduled_trigger(job_id: str) -> Dict[str, str]:
    """Cancel a scheduled trigger by its job ID.

    Args:
        job_id: The job ID returned from schedule_agent_prompt or list_scheduled_triggers

    Returns:
        Confirmation message

    Example:
        cancel_scheduled_trigger("interval_123")
    """
    scheduler = _get_trigger_scheduler()
    success = scheduler.remove_job(job_id)

    if success:
        return {
            "status": "success",
            "message": f"Cancelled job {job_id}",
        }
    else:
        return {
            "status": "error",
            "message": f"Job {job_id} not found",
        }


@tool
async def on_data_update_run_agent(
    source_name: str,
    symbol: str,
    resolution: str,
    prompt_template: str,
) -> Dict[str, str]:
    """Set up an agent to run whenever new data arrives for a specific symbol.

    The prompt_template can include {variables} that will be filled with bar data:
    - {time}: Bar timestamp
    - {open}, {high}, {low}, {close}, {volume}: OHLCV values
    - {symbol}: Trading pair symbol
    - {source}: Data source name

    Args:
        source_name: Name of data source (e.g., "binance")
        symbol: Trading pair (e.g., "BTC/USDT")
        resolution: Time resolution (e.g., "1m", "5m", "1h")
        prompt_template: Template string for agent prompt

    Returns:
        Confirmation with subscription details

    Example:
        on_data_update_run_agent(
            source_name="binance",
            symbol="BTC/USDT",
            resolution="1m",
            prompt_template="New bar on {symbol}: close={close}. Check if we should trade."
        )

    Note:
        This is a simplified version. Full implementation would wire into
        DataSource subscription system to trigger on every bar update.
    """
    # TODO: Implement proper DataSource subscription integration
    # For now, return placeholder

    return {
        "status": "not_implemented",
        "message": "Data-driven agent triggers coming soon",
        "config": {
            "source": source_name,
            "symbol": symbol,
            "resolution": resolution,
            "prompt_template": prompt_template,
        },
    }


@tool
def get_trigger_system_stats() -> Dict[str, Any]:
    """Get statistics about the trigger system.

    Returns:
        Dictionary with queue depth, execution stats, etc.

    Example:
        stats = get_trigger_system_stats()
        print(f"Queue depth: {stats['queue_depth']}")
        print(f"Current seq: {stats['current_seq']}")
    """
    queue = _get_trigger_queue()
    coordinator = _get_coordinator()

    return {
        "queue_depth": queue.get_queue_size(),
        "queue_running": queue.is_running(),
        "coordinator_stats": coordinator.get_stats(),
    }


# Export tools list
TRIGGER_TOOLS = [
    schedule_agent_prompt,
    execute_agent_prompt_once,
    list_scheduled_triggers,
    cancel_scheduled_trigger,
    on_data_update_run_agent,
    get_trigger_system_stats,
]
