"""
scheduler.py — MoneyMaker worker daemon.

Runs the pipeline at scheduled times (Mon-Fri UTC):
  04:00  analyze-only  (NLP before Copenhagen market open 09:00 CET)
  07:30  trade window 1
  10:00  trade window 2
  12:30  trade window 3
  14:30  trade window 4
  17:00  daily P&L report

Outputs appended to LOG_DIR/runner_YYYY-MM-DD.log so the dashboard can
show a live log tail. Uses only stdlib — no extra scheduler dependency.
"""
import os
import sys
import time
import traceback
from datetime import datetime, timezone
from pathlib import Path

LOG_DIR = Path(os.getenv("LOG_DIR", str(Path(__file__).parent / "data" / "logs")))
LOG_DIR.mkdir(parents=True, exist_ok=True)

# hour, minute, weekdays (0=Mon…4=Fri), analyze_only, is_report
SCHEDULE = [
    (4,  0,  frozenset(range(5)), True,  False),
    (7,  30, frozenset(range(5)), False, False),
    (10, 0,  frozenset(range(5)), False, False),
    (12, 30, frozenset(range(5)), False, False),
    (14, 30, frozenset(range(5)), False, False),
    (17, 0,  frozenset(range(5)), False, True),
]

# Saxo's access token lasts ~20 min and its refresh token rolls on each refresh
# but lapses if unused for ~1h. Trade windows are 2-3h apart, so we roll the
# token forward here independently to keep the refresh chain alive between runs.
SAXO_KEEPALIVE_SEC = 300


def _saxo_keepalive() -> None:
    """Roll the Saxo OAuth token forward so its refresh token never lapses in the
    gaps between scheduled runs. No-op when there's no stored OAuth token yet
    (e.g. only the 24h env token is present)."""
    try:
        from saxo_auth import _load, get_token
        if _load().get("refresh_token"):
            get_token()  # auto-refreshes when near expiry; rolls the refresh token
    except Exception as exc:
        print(f"[scheduler] saxo keep-alive: {exc}", flush=True)


def _log_path() -> Path:
    today = datetime.now(timezone.utc).strftime("%Y-%m-%d")
    return LOG_DIR / f"runner_{today}.log"


def _run_job(analyze_only: bool, is_report: bool) -> None:
    log = _log_path()
    with open(log, "a", buffering=1) as fh:
        old_out, old_err = sys.stdout, sys.stderr
        sys.stdout = sys.stderr = fh
        try:
            if is_report:
                from report import print_report
                print_report()
            else:
                from runner import run_pipeline
                run_pipeline(analyze_only=analyze_only)
        except Exception as exc:
            print(f"[scheduler] ERROR: {exc}")
            traceback.print_exc()
        finally:
            sys.stdout = old_out
            sys.stderr = old_err


def main() -> None:
    last_run: dict = {}
    last_keepalive = 0.0
    print(f"[scheduler] started — LOG_DIR={LOG_DIR}", flush=True)

    while True:
        now = datetime.now(timezone.utc)

        # Keep the Saxo refresh-token chain alive between trade windows.
        if time.time() - last_keepalive >= SAXO_KEEPALIVE_SEC:
            last_keepalive = time.time()
            _saxo_keepalive()

        dow = now.weekday()

        for hour, minute, days, analyze_only, is_report in SCHEDULE:
            if dow not in days:
                continue
            key = (hour, minute, now.date())
            if key in last_run:
                continue
            if now.hour == hour and now.minute == minute:
                last_run[key] = True
                label = "report" if is_report else ("analyze-only" if analyze_only else "full")
                print(f"[scheduler] {now.strftime('%H:%M UTC')} — {label}", flush=True)
                _run_job(analyze_only, is_report)
                print(f"[scheduler] {label} done", flush=True)

        time.sleep(30)


if __name__ == "__main__":
    main()
