"""Trigger system (IFTTT) pipeline functions."""

from __future__ import annotations

import logging
import threading
import time
from dataclasses import dataclass, field
from typing import Any, Callable

from horizon._horizon import (
    TriggerCondition,
    TriggerActionType,
    TriggerRule,
    TriggerResult,
    evaluate_trigger,
    create_trigger,
)

logger = logging.getLogger("horizon")


@dataclass
class TriggerConfig:
    """Configuration for a trigger rule."""
    name: str
    feed_name: str
    condition: str = "above"  # above, below, cross_above, cross_below, percent_change, absolute_change, between, outside
    threshold: float = 0.5
    threshold_upper: float = 0.0
    action: str = "alert"  # alert, webhook, order, hedge, kill_switch
    cooldown_secs: float = 60.0
    hysteresis: float = 0.0
    webhook_url: str = ""
    order_side: str = "buy"
    order_size: float = 10.0


_CONDITION_MAP = {
    "above": TriggerCondition.Above,
    "below": TriggerCondition.Below,
    "cross_above": TriggerCondition.CrossAbove,
    "cross_below": TriggerCondition.CrossBelow,
    "percent_change": TriggerCondition.PercentChange,
    "absolute_change": TriggerCondition.AbsoluteChange,
    "between": TriggerCondition.Between,
    "outside": TriggerCondition.Outside,
}

_ACTION_MAP = {
    "alert": TriggerActionType.Alert,
    "webhook": TriggerActionType.Webhook,
    "order": TriggerActionType.Order,
    "hedge": TriggerActionType.Hedge,
    "kill_switch": TriggerActionType.KillSwitch,
}


def trigger(
    triggers: list[TriggerConfig],
    alert_manager: Any = None,
) -> Callable:
    """Evaluate triggers each cycle and fire actions."""
    from horizon._horizon import auth_require_ultra
    auth_require_ultra()

    # Mutable state per trigger
    state: dict[str, dict] = {}

    def _fn(ctx) -> dict[str, Any]:
        fired = []

        for tc in triggers:
            feed = ctx.feeds.get(tc.feed_name)
            if not feed:
                continue

            s = state.setdefault(tc.name, {
                "prev_value": 0.0,
                "last_fire": 0.0,
                "armed": True,
            })

            condition = _CONDITION_MAP.get(tc.condition, TriggerCondition.Above)
            action = _ACTION_MAP.get(tc.action, TriggerActionType.Alert)

            rule = create_trigger(
                tc.name, condition, tc.threshold, action,
                tc.threshold_upper, tc.cooldown_secs, tc.hysteresis,
            )

            now = time.time()
            result = evaluate_trigger(
                rule, feed.price, s["prev_value"],
                s["last_fire"], now, s["armed"],
            )

            s["prev_value"] = feed.price

            if result.fired:
                s["last_fire"] = now
                fired.append({
                    "name": result.rule_name,
                    "action": tc.action,
                    "value": result.current_value,
                    "reason": result.reason,
                })

                # Execute actions
                if tc.action == "webhook" and tc.webhook_url:
                    _fire_webhook(tc.webhook_url, result)
                elif tc.action == "alert" and alert_manager:
                    try:
                        alert_manager.send(f"Trigger fired: {tc.name} - {result.reason}")
                    except Exception:
                        pass

                logger.info("Trigger fired: %s - %s", tc.name, result.reason)

        return {"fired": fired, "num_fired": len(fired)}

    _fn.__name__ = "trigger"
    return _fn


def conditional_hedge(
    feed_name: str,
    condition: str = "below",
    threshold: float = 0.3,
    hedge_size: float = 100.0,
    cooldown_secs: float = 300.0,
) -> Callable:
    """Automatically hedge when a condition is met."""
    from horizon._horizon import auth_require_ultra
    auth_require_ultra()

    last_fire = [0.0]
    prev_value = [0.0]

    def _fn(ctx) -> dict[str, Any]:
        feed = ctx.feeds.get(feed_name)
        if not feed:
            return {"hedge_triggered": False}

        cond = _CONDITION_MAP.get(condition, TriggerCondition.Below)
        rule = create_trigger(
            "auto_hedge", cond, threshold, TriggerActionType.Hedge,
            0.0, cooldown_secs, 0.0,
        )

        now = time.time()
        result = evaluate_trigger(rule, feed.price, prev_value[0], last_fire[0], now, True)
        prev_value[0] = feed.price

        if result.fired:
            last_fire[0] = now
            return {
                "hedge_triggered": True,
                "hedge_size": hedge_size,
                "reason": result.reason,
            }

        return {"hedge_triggered": False, "current_value": feed.price}

    _fn.__name__ = "conditional_hedge"
    return _fn


def oracle(port: int = 8099) -> Callable:
    """Start a minimal HTTP server exposing feed prices as JSON.

    GET / returns {"feeds": {"name": price, ...}}.
    """
    from horizon._horizon import auth_require_ultra
    auth_require_ultra()

    import http.server
    import json

    latest_data: dict[str, float] = {}
    server_started = [False]

    class Handler(http.server.BaseHTTPRequestHandler):
        def do_GET(self):
            self.send_response(200)
            self.send_header("Content-Type", "application/json")
            self.end_headers()
            self.wfile.write(json.dumps({"feeds": latest_data}).encode())

        def log_message(self, format, *args):
            pass  # suppress logs

    def _start_server():
        try:
            srv = http.server.HTTPServer(("0.0.0.0", port), Handler)
            srv.serve_forever()
        except Exception as e:
            logger.warning("Oracle server failed: %s", e)

    def _fn(ctx) -> dict[str, Any]:
        for name, feed in ctx.feeds.items():
            if feed and feed.price > 0:
                latest_data[name] = feed.price

        if not server_started[0]:
            t = threading.Thread(target=_start_server, daemon=True)
            t.start()
            server_started[0] = True
            logger.info("Oracle server started on port %d", port)

        return {"oracle_port": port, "num_feeds": len(latest_data)}

    _fn.__name__ = "oracle"
    return _fn


def _fire_webhook(url: str, result: TriggerResult) -> None:
    """Fire-and-forget webhook."""
    import json
    import urllib.request

    def _send():
        try:
            data = json.dumps({
                "trigger": result.rule_name,
                "value": result.current_value,
                "threshold": result.threshold,
                "reason": result.reason,
            }).encode()
            req = urllib.request.Request(url, data=data, headers={"Content-Type": "application/json"})
            urllib.request.urlopen(req, timeout=5)
        except Exception as e:
            logger.debug("Webhook failed: %s", e)

    threading.Thread(target=_send, daemon=True).start()
