"""Calendar/event integration pipeline functions."""

from __future__ import annotations

import logging
from typing import Any, Callable

logger = logging.getLogger("horizon")

# Bundled FOMC dates 2024-2026
FOMC_DATES = [
    # 2024
    "2024-01-31", "2024-03-20", "2024-05-01", "2024-06-12",
    "2024-07-31", "2024-09-18", "2024-11-07", "2024-12-18",
    # 2025
    "2025-01-29", "2025-03-19", "2025-05-07", "2025-06-18",
    "2025-07-30", "2025-09-17", "2025-11-05", "2025-12-17",
    # 2026
    "2026-01-28", "2026-03-18", "2026-05-06", "2026-06-17",
    "2026-07-29", "2026-09-16", "2026-11-04", "2026-12-16",
]

# Bundled CPI release dates 2025-2026
CPI_DATES = [
    "2025-01-15", "2025-02-12", "2025-03-12", "2025-04-10",
    "2025-05-13", "2025-06-11", "2025-07-11", "2025-08-12",
    "2025-09-10", "2025-10-14", "2025-11-12", "2025-12-10",
    "2026-01-14", "2026-02-11", "2026-03-11", "2026-04-14",
    "2026-05-12", "2026-06-10", "2026-07-14", "2026-08-12",
    "2026-09-15", "2026-10-13", "2026-11-10", "2026-12-09",
]


def _dates_to_events(dates: list[str], event_type: str, name_prefix: str) -> list[dict]:
    """Convert date strings to event dicts with timestamps."""
    import datetime
    events = []
    for d in dates:
        try:
            dt = datetime.datetime.strptime(d, "%Y-%m-%d").replace(
                hour=14, minute=0  # 2pm ET default
            )
            events.append({
                "name": f"{name_prefix} {d}",
                "timestamp": dt.timestamp(),
                "type": event_type,
            })
        except ValueError:
            continue
    return events


def bundled_events_json() -> str:
    """Get bundled FOMC + CPI events as JSON string."""
    import json
    events = _dates_to_events(FOMC_DATES, "fomc", "FOMC")
    events += _dates_to_events(CPI_DATES, "cpi", "CPI")
    return json.dumps(events)


def time_decay(
    calendar_feed: str = "calendar",
    max_days: float = 30.0,
    decay_type: str = "linear",
) -> Callable:
    """Apply time decay sizing based on distance to next event.

    Reduces position size as events approach (risk management).
    """
    from horizon._horizon import auth_require_ultra
    auth_require_ultra()

    def _fn(ctx) -> dict[str, Any]:
        feed = ctx.feeds.get(calendar_feed)
        if not feed:
            return {"time_decay_factor": 1.0, "days_to_event": float("inf")}

        days = feed.volume_24h  # days to event stored here
        event_type = feed.ask  # event type code

        if decay_type == "exponential":
            factor = 1.0 - (2.718 ** (-days / max_days))
        elif decay_type == "sqrt":
            factor = min(1.0, (days / max_days) ** 0.5)
        else:  # linear
            factor = min(1.0, days / max_days)

        return {
            "time_decay_factor": factor,
            "days_to_event": days,
            "event_urgency": feed.price,
            "event_type_code": event_type,
        }

    _fn.__name__ = "time_decay"
    return _fn


def event_countdown(
    calendar_feed: str = "calendar",
) -> Callable:
    """Expose event countdown data for downstream pipeline use."""
    from horizon._horizon import auth_require_ultra
    auth_require_ultra()

    def _fn(ctx) -> dict[str, Any]:
        feed = ctx.feeds.get(calendar_feed)
        if not feed:
            return {
                "seconds_to_event": float("inf"),
                "event_name": "",
                "event_type_code": 0.0,
                "urgency": 0.0,
            }

        return {
            "seconds_to_event": feed.bid,
            "event_name": feed.source.replace("calendar:", ""),
            "event_type_code": feed.ask,
            "urgency": feed.price,
            "days_to_event": feed.volume_24h,
        }

    _fn.__name__ = "event_countdown"
    return _fn


def pre_event_strategy(
    calendar_feed: str = "calendar",
    reduce_hours: float = 24.0,
    reduce_factor: float = 0.5,
) -> Callable:
    """Reduce exposure before major events."""
    from horizon._horizon import auth_require_ultra
    auth_require_ultra()

    reduce_secs = reduce_hours * 3600.0

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

        secs = feed.bid  # seconds to event
        pre_event = 0 < secs < reduce_secs

        if pre_event:
            # Linear ramp: full reduction at event, none at reduce_hours before
            ramp = max(0.0, secs / reduce_secs)
            mult = reduce_factor + (1.0 - reduce_factor) * ramp
        else:
            mult = 1.0

        return {
            "size_multiplier": mult,
            "pre_event": pre_event,
            "seconds_to_event": secs,
            "event_name": feed.source.replace("calendar:", ""),
        }

    _fn.__name__ = "pre_event_strategy"
    return _fn
