"""
Isolated Cycle Actions — callable individually from UI or cron.

Decomposition of the full auto_cycle into 8 independent actions:

  ACTION 1 — check-market-events    ← IMPLEMENTED HERE
    Sources: RSS news + FRED eco surprises + MA crossovers + institutional reports
    Output : new market_events created in DB

  ACTION 2 — refresh-price-data      (planned)
    Sources: yfinance OHLCV for all watchlist instruments
    Output : price_data table updated

  ACTION 3 — compute-indicators      (planned)
    Sources: price_data in DB
    Output : ma20/50/100/200 + RSI + BB + ATR stored in instrument_indicators

  ACTION 4 — evaluate-impacts        (planned)
    Sources: market_events without impact scores
    Output : GPT-evaluated impact_score + affected_assets stored

  ACTION 5 — generate-signals        (planned)
    Sources: indicators + market_events + portfolio
    Output : trading signals for each instrument

  ACTION 6 — update-regime           (planned)
    Sources: signals + macro context
    Output : current macro_regime classification

  ACTION 7 — snapshot-portfolio      (planned)
    Sources: portfolio positions + current prices
    Output : risk metrics (VaR, PnL, delta) snapshot stored

  ACTION 8 — generate-report         (planned)
    Sources: all of the above
    Output : daily cycle report PDF/JSON
"""
import logging
from datetime import datetime
from typing import Any, Dict, List, Optional

from fastapi import APIRouter, BackgroundTasks, HTTPException, Query
from pydantic import BaseModel

logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/actions", tags=["Cycle Actions"])


# ── Request / Response models ─────────────────────────────────────────────────

class CheckEventsRequest(BaseModel):
    sources: Optional[List[str]] = None          # ['news','eco','technical','reports']
    news_impact_min: float = 0.55
    news_lookback_hours: int = 48
    eco_z_threshold: float = 1.5
    eco_days: int = 7
    technical_lookback_days: int = 7
    report_days: int = 7
    report_min_importance: int = 3


class ActionResult(BaseModel):
    action: str
    status: str
    started_at: str
    finished_at: str
    duration_s: float
    total_created: int
    detail: Dict[str, Any]


# ── In-memory run state (prevents concurrent duplicate runs) ──────────────────
_running: Dict[str, bool] = {}


def _guard(action: str) -> None:
    if _running.get(action):
        raise HTTPException(status_code=409, detail=f"Action '{action}' is already running")
    _running[action] = True


def _release(action: str) -> None:
    _running.pop(action, None)


# ── GET /api/actions — list all actions with status ───────────────────────────

@router.get("")
def list_actions():
    """Return the catalogue of available cycle actions and their run status."""
    actions = [
        {
            "id":          "check-market-events",
            "label":       "Check New Market Events",
            "description": "Scans RSS news, FRED eco surprises, MA crossovers, and institutional reports to create new market_events.",
            "status":      "running" if _running.get("check-market-events") else "idle",
            "implemented": True,
            "group":       "detection",
        },
        {
            "id":          "bootstrap-macro",
            "label":       "Bootstrap Macro Events",
            "description": "Seed 30+ historical macro/geopolitical events (FOMC, NFP, elections…). Idempotent — skip duplicates.",
            "status":      "running" if _running.get("bootstrap-macro") else "idle",
            "implemented": True,
            "group":       "bootstrap",
        },
        {
            "id":          "bootstrap-eco",
            "label":       "Bootstrap Eco Calendar",
            "description": "Seed economic calendar events from FRED/ECB/BOE (last 12 months). Idempotent.",
            "status":      "running" if _running.get("bootstrap-eco") else "idle",
            "implemented": True,
            "group":       "bootstrap",
        },
        {
            "id":          "bootstrap-categories",
            "label":       "Bootstrap Impact Categories",
            "description": "Seed default event categories with instrument impact weights (FOMC, NFP, CPI, BOE…).",
            "status":      "running" if _running.get("bootstrap-categories") else "idle",
            "implemented": True,
            "group":       "bootstrap",
        },
        {"id": "bootstrap-ma",       "label": "Bootstrap MA Crossovers", "description": "Detect historical MA50/100/200 crossovers for all instruments.", "status": "idle", "implemented": False, "group": "bootstrap"},
        {"id": "refresh-price-data", "label": "Refresh Price Data",      "description": "Download fresh OHLCV for all watchlist instruments.", "status": "idle", "implemented": False, "group": "data"},
        {"id": "compute-indicators", "label": "Compute Indicators",      "description": "Recalculate MA/RSI/BB/ATR for all instruments.", "status": "idle", "implemented": False, "group": "data"},
        {"id": "evaluate-impacts",   "label": "Evaluate Impacts",        "description": "AI-score market_events that lack impact_score.", "status": "idle", "implemented": False, "group": "ai"},
        {"id": "generate-signals",   "label": "Generate Signals",        "description": "Compute trading signals from indicators + events.", "status": "idle", "implemented": False, "group": "ai"},
        {"id": "update-regime",      "label": "Update Regime",           "description": "Re-classify the current macro regime.", "status": "idle", "implemented": False, "group": "ai"},
        {"id": "snapshot-portfolio", "label": "Snapshot Portfolio",      "description": "Store a risk snapshot (VaR, PnL, delta).", "status": "idle", "implemented": False, "group": "portfolio"},
        {"id": "generate-report",    "label": "Generate Report",         "description": "Build and persist the daily cycle report.", "status": "idle", "implemented": False, "group": "portfolio"},
    ]
    return {"actions": actions}


# ── POST /api/actions/check-market-events ─────────────────────────────────────

@router.post("/check-market-events", response_model=ActionResult)
def check_market_events(req: CheckEventsRequest):
    """
    ACTION 1 — Check New Market Events.

    Runs synchronously (up to ~60 s with yfinance + OpenAI calls).
    Returns counts of created events per source.
    """
    _guard("check-market-events")
    started_at = datetime.utcnow()

    try:
        from services.market_event_detector import check_new_market_events
        result = check_new_market_events(
            sources=req.sources,
            news_impact_min=req.news_impact_min,
            news_lookback_hours=req.news_lookback_hours,
            eco_z_threshold=req.eco_z_threshold,
            eco_days=req.eco_days,
            technical_lookback_days=req.technical_lookback_days,
            report_days=req.report_days,
            report_min_importance=req.report_min_importance,
        )
    except Exception as e:
        _release("check-market-events")
        logger.error(f"[action/check-market-events] {e}")
        raise HTTPException(status_code=500, detail=str(e))

    _release("check-market-events")
    finished_at = datetime.utcnow()
    duration_s  = (finished_at - started_at).total_seconds()

    return ActionResult(
        action="check-market-events",
        status="success",
        started_at=started_at.isoformat(),
        finished_at=finished_at.isoformat(),
        duration_s=round(duration_s, 2),
        total_created=result.get("total_created", 0),
        detail={
            "news":      result.get("news", []),
            "eco":       result.get("eco", []),
            "technical": result.get("technical", []),
            "reports":   result.get("reports", []),
        },
    )


# ── POST /api/actions/check-market-events/background ─────────────────────────

@router.post("/check-market-events/background", status_code=202)
def check_market_events_background(
    req: CheckEventsRequest,
    background_tasks: BackgroundTasks,
):
    """
    Fire-and-forget version — returns 202 immediately.
    Results are only visible via logs (system_logs table or backend console).
    """
    if _running.get("check-market-events"):
        raise HTTPException(status_code=409, detail="Action 'check-market-events' is already running")

    def _run():
        _guard("check-market-events")
        try:
            from services.market_event_detector import check_new_market_events
            check_new_market_events(
                sources=req.sources,
                news_impact_min=req.news_impact_min,
                news_lookback_hours=req.news_lookback_hours,
                eco_z_threshold=req.eco_z_threshold,
                eco_days=req.eco_days,
                technical_lookback_days=req.technical_lookback_days,
                report_days=req.report_days,
                report_min_importance=req.report_min_importance,
            )
        except Exception as e:
            logger.error(f"[action/check-market-events/bg] {e}")
        finally:
            _release("check-market-events")

    background_tasks.add_task(_run)
    return {"status": "accepted", "message": "check-market-events started in background"}


# ── POST /api/actions/bootstrap-macro ────────────────────────────────────────

@router.post("/bootstrap-macro")
def run_bootstrap_macro(force: bool = Query(False)):
    """Seed macro/geopolitical historical events. Idempotent by default."""
    _guard("bootstrap-macro")
    try:
        from services.macro_events_bootstrap import bootstrap_macro_events
        result = bootstrap_macro_events(force=force)
    except Exception as e:
        _release("bootstrap-macro")
        raise HTTPException(500, str(e))
    _release("bootstrap-macro")
    return {"action": "bootstrap-macro", "status": "success", **result}


# ── POST /api/actions/bootstrap-eco ──────────────────────────────────────────

@router.post("/bootstrap-eco")
def run_bootstrap_eco(force: bool = Query(False)):
    """Seed economic calendar events. Idempotent by default."""
    _guard("bootstrap-eco")
    try:
        from services.eco_calendar_bootstrap import bootstrap_eco_events
        result = bootstrap_eco_events(force=force)
    except Exception as e:
        _release("bootstrap-eco")
        raise HTTPException(500, str(e))
    _release("bootstrap-eco")
    return {"action": "bootstrap-eco", "status": "success", **result}


# ── POST /api/actions/bootstrap-categories ────────────────────────────────────

@router.post("/bootstrap-categories")
def run_bootstrap_categories(force: bool = Query(False)):
    """Seed default event categories with impact weights. Idempotent."""
    _guard("bootstrap-categories")
    try:
        from services.impact_categories_bootstrap import bootstrap_impact_categories
        result = bootstrap_impact_categories(force=force)
    except Exception as e:
        _release("bootstrap-categories")
        raise HTTPException(500, str(e))
    _release("bootstrap-categories")
    return {"action": "bootstrap-categories", "status": "success", **result}
