"""An alpaca-py bot trading a tradefloor session. Only the base URL changes.

    python -m tradefloor_serve                  # a local server, in another terminal
    python examples/agents/alpaca_bot.py --days 10

For the hosted service, set TF_URL=https://app.tradefloor.dev and
TF_KEY=tfk_...; the key goes where alpaca-py puts the secret.

The strategy is a moving-average crossover on daily bars: hold a name while
its last close is above its 5-day average. The one line that is not Alpaca
is the advance call, where a live bot would sleep until the next day.
"""

from __future__ import annotations

import argparse
import os
from datetime import datetime

import httpx
from alpaca.data.historical import StockHistoricalDataClient
from alpaca.data.requests import StockBarsRequest
from alpaca.data.timeframe import TimeFrame
from alpaca.trading.client import TradingClient
from alpaca.trading.enums import OrderSide, TimeInForce
from alpaca.trading.requests import MarketOrderRequest

BASE = os.environ.get("TF_URL", "http://127.0.0.1:8765")
KEY = os.environ.get("TF_KEY") or "self-run"   # alpaca-py wants a non-empty key


def open_session() -> str:
    """Sessions are opened on the native API; the facade trades them."""
    r = httpx.post(f"{BASE}/v1/sessions", json={"universe_size": 6, "seed": 11, "label": "alpaca_bot"},
                   headers={"Authorization": f"Bearer {KEY}"}, timeout=30)
    r.raise_for_status()
    return r.json()["session_id"]


def main() -> None:
    parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
    parser.add_argument("--days", type=int, default=10)
    args = parser.parse_args()

    session_id = open_session()
    url = f"{BASE}/broker/{session_id}"
    trading = TradingClient("tradefloor", KEY, url_override=url)
    data = StockHistoricalDataClient("tradefloor", KEY, url_override=url)
    symbols = [a.symbol for a in trading.get_all_assets()]
    print(f"session {session_id}: {', '.join(symbols)}")

    for _ in range(args.days):
        clock = trading.get_clock()
        bars = data.get_stock_bars(StockBarsRequest(
            symbol_or_symbols=symbols, timeframe=TimeFrame.Day, start=datetime(2000, 1, 1))).data
        held = {p.symbol: float(p.qty) for p in trading.get_all_positions()}
        cash = float(trading.get_account().cash)
        for symbol in symbols:
            closes = [b.close for b in bars.get(symbol, [])][-5:]
            if len(closes) < 5:
                continue
            above = closes[-1] > sum(closes) / len(closes)
            if above and symbol not in held:
                qty = int(cash * 0.15 // closes[-1])
                if qty:
                    trading.submit_order(MarketOrderRequest(
                        symbol=symbol, qty=qty, side=OrderSide.BUY, time_in_force=TimeInForce.DAY,
                        client_order_id=f"{clock.timestamp.date()}-buy-{symbol}"))
            elif not above and held.get(symbol, 0) > 0:
                trading.close_position(symbol)
        # Where a live bot would sleep until tomorrow: run today, open tomorrow.
        trading.post("/tradefloor/advance", {"until": "next_open"})

    account = trading.get_account()
    print(f"after {args.days} days: equity {float(account.equity):,.2f}, cash {float(account.cash):,.2f}, "
          f"{len(trading.get_all_positions())} positions")
    report = httpx.post(f"{BASE}/v1/sessions/{session_id}/close",
                        headers={"Authorization": f"Bearer {KEY}"}, timeout=30).json()
    print(f"closed: {report['fills']} fills over {report['days']} days; "
          f"{len(report['caveats'])} caveats, the first: {report['caveats'][0]}")


if __name__ == "__main__":
    main()
