"""
Trigger handlers - concrete implementations for common trigger types.

Provides ready-to-use trigger handlers for:
- Agent execution (WebSocket user messages)
- Lambda/callable execution
- Data update triggers
- Indicator updates
"""

import logging
import time
from typing import Any, Awaitable, Callable, Optional

from .coordinator import CommitCoordinator
from .types import CommitIntent, Priority, Trigger

logger = logging.getLogger(__name__)


class AgentTriggerHandler(Trigger):
    """
    Trigger for agent execution from WebSocket user messages.

    Wraps the Gateway's agent execution flow and captures any
    store modifications as commit intents.

    Priority tuple: (USER_AGENT, message_timestamp, queue_seq)
    """

    def __init__(
        self,
        session_id: str,
        message_content: str,
        message_timestamp: Optional[int] = None,
        attachments: Optional[list] = None,
        gateway_handler: Optional[Callable] = None,
        coordinator: Optional[CommitCoordinator] = None,
    ):
        """
        Initialize agent trigger.

        Args:
            session_id: User session ID
            message_content: User message content
            message_timestamp: When user sent message (unix timestamp, defaults to now)
            attachments: Optional message attachments
            gateway_handler: Callable to route to Gateway (set during integration)
            coordinator: CommitCoordinator for accessing stores
        """
        if message_timestamp is None:
            message_timestamp = int(time.time())

        # Priority tuple: sort by USER_AGENT priority, then message timestamp
        super().__init__(
            name=f"agent_{session_id}",
            priority=Priority.USER_AGENT,
            priority_tuple=(Priority.USER_AGENT.value, message_timestamp)
        )
        self.session_id = session_id
        self.message_content = message_content
        self.message_timestamp = message_timestamp
        self.attachments = attachments or []
        self.gateway_handler = gateway_handler
        self.coordinator = coordinator

    async def execute(self) -> list[CommitIntent]:
        """
        Execute agent interaction.

        This will call into the Gateway, which will run the agent.
        The agent may read from stores and generate responses.
        Any store modifications are captured as commit intents.

        Returns:
            List of commit intents (typically empty for now, as agent
            modifies stores via tools which will be integrated later)
        """
        if not self.gateway_handler:
            logger.error("No gateway_handler configured for AgentTriggerHandler")
            return []

        logger.info(
            f"Agent trigger executing: session={self.session_id}, "
            f"content='{self.message_content[:50]}...'"
        )

        try:
            # Call Gateway to handle message
            # In future, Gateway/agent tools will use coordinator stores
            await self.gateway_handler(
                self.session_id,
                self.message_content,
                self.attachments,
            )

            # For now, agent doesn't directly modify stores
            # Future: agent tools will return commit intents
            return []

        except Exception as e:
            logger.error(f"Agent execution error: {e}", exc_info=True)
            raise


class LambdaHandler(Trigger):
    """
    Generic trigger that executes an arbitrary async callable.

    Useful for custom triggers, one-off tasks, or testing.
    """

    def __init__(
        self,
        name: str,
        func: Callable[[], Awaitable[list[CommitIntent]]],
        priority: Priority = Priority.SYSTEM,
    ):
        """
        Initialize lambda handler.

        Args:
            name: Descriptive name for this trigger
            func: Async callable that returns commit intents
            priority: Execution priority
        """
        super().__init__(name, priority)
        self.func = func

    async def execute(self) -> list[CommitIntent]:
        """Execute the callable"""
        logger.info(f"Lambda trigger executing: {self.name}")
        return await self.func()


class DataUpdateTrigger(Trigger):
    """
    Trigger for DataSource bar updates.

    Fired when new market data arrives. Can update indicators,
    trigger strategy logic, or notify the agent of market events.

    Priority tuple: (DATA_SOURCE, event_time, queue_seq)
    Ensures older bars process before newer ones.
    """

    def __init__(
        self,
        source_name: str,
        symbol: str,
        resolution: str,
        bar_data: dict,
        coordinator: Optional[CommitCoordinator] = None,
    ):
        """
        Initialize data update trigger.

        Args:
            source_name: Name of data source (e.g., "binance")
            symbol: Trading pair symbol
            resolution: Time resolution
            bar_data: Bar data dict (time, open, high, low, close, volume)
            coordinator: CommitCoordinator for accessing stores
        """
        event_time = bar_data.get('time', int(time.time()))

        # Priority tuple: sort by DATA_SOURCE priority, then event time
        super().__init__(
            name=f"data_{source_name}_{symbol}_{resolution}",
            priority=Priority.DATA_SOURCE,
            priority_tuple=(Priority.DATA_SOURCE.value, event_time)
        )
        self.source_name = source_name
        self.symbol = symbol
        self.resolution = resolution
        self.bar_data = bar_data
        self.coordinator = coordinator

    async def execute(self) -> list[CommitIntent]:
        """
        Process bar update.

        Future implementations will:
        - Update indicator values
        - Check strategy conditions
        - Trigger alerts/notifications

        Returns:
            Commit intents for any store updates
        """
        logger.info(
            f"Data update trigger: {self.source_name}:{self.symbol}@{self.resolution}, "
            f"time={self.bar_data.get('time')}"
        )

        # TODO: Update indicators
        # TODO: Check strategy conditions
        # TODO: Notify agent of significant events

        # For now, just log
        return []


class IndicatorUpdateTrigger(Trigger):
    """
    Trigger for updating indicator values.

    Can be fired by cron (periodic recalculation) or by data updates.
    """

    def __init__(
        self,
        indicator_id: str,
        force_full_recalc: bool = False,
        coordinator: Optional[CommitCoordinator] = None,
        priority: Priority = Priority.SYSTEM,
    ):
        """
        Initialize indicator update trigger.

        Args:
            indicator_id: ID of indicator to update
            force_full_recalc: If True, recalculate entire history
            coordinator: CommitCoordinator for accessing stores
            priority: Execution priority
        """
        super().__init__(f"indicator_{indicator_id}", priority)
        self.indicator_id = indicator_id
        self.force_full_recalc = force_full_recalc
        self.coordinator = coordinator

    async def execute(self) -> list[CommitIntent]:
        """
        Update indicator value.

        Reads from IndicatorStore, recalculates, prepares commit.

        Returns:
            Commit intents for updated indicator data
        """
        if not self.coordinator:
            logger.error("No coordinator configured")
            return []

        # Get indicator store
        indicator_store = self.coordinator.get_store("IndicatorStore")
        if not indicator_store:
            logger.error("IndicatorStore not registered")
            return []

        # Read snapshot
        snapshot_seq, indicator_data = indicator_store.read_snapshot()

        logger.info(
            f"Indicator update trigger: {self.indicator_id}, "
            f"snapshot_seq={snapshot_seq}, force_full={self.force_full_recalc}"
        )

        # TODO: Implement indicator recalculation logic
        # For now, just return empty (no changes)

        return []


class CronTrigger(Trigger):
    """
    Trigger fired by APScheduler on a schedule.

    Wraps another trigger or callable to execute periodically.

    Priority tuple: (TIMER, scheduled_time, queue_seq)
    Ensures jobs scheduled for earlier times run first.
    """

    def __init__(
        self,
        name: str,
        inner_trigger: Trigger,
        scheduled_time: Optional[int] = None,
    ):
        """
        Initialize cron trigger.

        Args:
            name: Descriptive name (e.g., "hourly_sync")
            inner_trigger: Trigger to execute on schedule
            scheduled_time: When this was scheduled to run (defaults to now)
        """
        if scheduled_time is None:
            scheduled_time = int(time.time())

        # Priority tuple: sort by TIMER priority, then scheduled time
        super().__init__(
            name=f"cron_{name}",
            priority=Priority.TIMER,
            priority_tuple=(Priority.TIMER.value, scheduled_time)
        )
        self.inner_trigger = inner_trigger
        self.scheduled_time = scheduled_time

    async def execute(self) -> list[CommitIntent]:
        """Execute the wrapped trigger"""
        logger.info(f"Cron trigger firing: {self.name}")
        return await self.inner_trigger.execute()
