"""
TradeStation MCP Server — Entry Point.

FastMCP server that exposes the full TradeStation API (MarketData, Brokerage,
Order Execution) as MCP tools. Uses OAuth2 Auth Code Flow for authentication.

Usage:
    python -m tradestation_mcp.server

Environment variables:
    TS_CLIENT_ID      — TradeStation API Key (required)
    TS_CLIENT_SECRET  — TradeStation API Secret (required)
    TS_REDIRECT_PORT  — Local OAuth callback port (default: 3000)
"""

import logging
import os
import sys

from dotenv import load_dotenv
from mcp.server.fastmcp import FastMCP

from .auth import TokenManager
from .client import TradeStationClient
from .tools.brokerage import register_brokerage_tools
from .tools.market_data import register_market_data_tools
from .tools.order_execution import register_order_execution_tools

# ── Logging setup (MUST go to stderr, never stdout — stdout is MCP STDIO transport)
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
    stream=sys.stderr,
)
logger = logging.getLogger("tradestation_mcp")

# ── Load environment variables
load_dotenv()

# ── Initialize FastMCP server
mcp = FastMCP(
    "tradestation",
    instructions="""TradeStation MCP Server — Access to TradeStation's full brokerage and market data API.

This server provides tools in three categories:

1. MARKET DATA tools — For stock prices, quotes, charts, option chains, symbol search.
   Use these when the user asks about stock/crypto/futures PRICES, historical data, or option analytics.
   Example: "What's the stock price of MSFT?" → get_quote_snapshots

2. BROKERAGE tools — For account info, balances, positions, order history.
   Use these when the user asks about THEIR account, money, holdings, or trade history.
   Example: "What's my account balance?" → get_balances

3. ORDER EXECUTION tools — For placing, modifying, and cancelling trades.
   Use these when the user wants to BUY, SELL, or manage orders.
   Example: "Buy 100 shares of MSFT" → confirm_order first, then place_order

Key routing rules:
- "What's the price of X?" → get_quote_snapshots (MARKET DATA)
- "What's my balance?" → get_balances (BROKERAGE)
- "What do I own?" → get_positions (BROKERAGE)
- "Buy/Sell X" → confirm_order then place_order (ORDER EXECUTION)
- ALWAYS call confirm_order before place_order to preview costs.
- Brokerage tools auto-resolve account IDs if not provided.
""",
)

# ── Globals for client (initialized on first use)
_token_manager: TokenManager | None = None
_ts_client: TradeStationClient | None = None


def _get_config():
    """Read and validate configuration from environment variables."""
    client_id = os.getenv("TS_CLIENT_ID", "").strip()
    client_secret = os.getenv("TS_CLIENT_SECRET", "").strip()
    redirect_port = int(os.getenv("TS_REDIRECT_PORT", "3000"))

    if not client_id:
        logger.error("TS_CLIENT_ID environment variable is required.")
        sys.exit(1)
    if not client_secret:
        logger.error("TS_CLIENT_SECRET environment variable is required.")
        sys.exit(1)

    return client_id, client_secret, redirect_port


def _init_clients():
    """Initialize token manager and API client."""
    global _token_manager, _ts_client

    if _ts_client is not None:
        return _ts_client

    client_id, client_secret, redirect_port = _get_config()

    _token_manager = TokenManager(
        client_id=client_id,
        client_secret=client_secret,
        redirect_port=redirect_port,
    )

    # Attempt authentication immediately so tokens are ready
    logger.info("Initializing TradeStation authentication...")
    _token_manager.ensure_authenticated()
    logger.info("Authentication successful.")

    _ts_client = TradeStationClient(_token_manager)
    return _ts_client


# ── Register MCP Prompts ───────────────────────────────────────────


@mcp.prompt()
def check_portfolio() -> str:
    """Review current portfolio — account balances, positions, and P&L summary.

    Use this prompt when the user wants a comprehensive portfolio overview.
    """
    return """Please provide a comprehensive portfolio summary by:
1. Call get_accounts to list all accounts
2. Call get_balances to get current cash, equity, and buying power for each account
3. Call get_positions to get all current holdings
4. Present a clear summary with:
   - Account overview (type, status)
   - Total equity, cash balance, buying power
   - Each position with symbol, quantity, average price, current price, unrealized P&L
   - Overall unrealized P&L across all positions"""


@mcp.prompt()
def get_stock_price(symbol: str) -> str:
    """Get the current market price and quote details for a stock symbol.

    Args:
        symbol: The ticker symbol to look up (e.g. "MSFT", "AAPL").
    """
    return f"""Get the current price quote for {symbol} by calling get_quote_snapshots with symbol "{symbol}".
Present the key details:
- Last trade price and time
- Net change and percentage change
- Bid/Ask prices and sizes
- Day's open, high, low
- Volume
- 52-week high and low"""


@mcp.prompt()
def place_trade(symbol: str, action: str, quantity: str) -> str:
    """Place a stock trade with confirmation preview first.

    Args:
        symbol: Ticker symbol (e.g. "MSFT").
        action: Trade action — "BUY", "SELL", etc.
        quantity: Number of shares/contracts.
    """
    return f"""To place a trade for {quantity} shares of {symbol} ({action}):
1. First call get_accounts to find the user's account ID
2. Call confirm_order with:
   - account_id from step 1
   - symbol="{symbol}"
   - quantity="{quantity}"
   - order_type="Market"
   - trade_action="{action}"
   - duration="DAY"
3. Show the estimated cost, commission, and summary to the user
4. Ask the user to explicitly confirm they want to place the order
5. ONLY after user confirmation, call place_order with the same parameters
6. Report the order ID and status"""


@mcp.prompt()
def analyze_options(underlying: str) -> str:
    """Analyze the options chain for a symbol with greeks and pricing.

    Args:
        underlying: The underlying symbol (e.g. "AAPL").
    """
    return f"""Analyze options for {underlying}:
1. Call get_option_expirations for "{underlying}" to see available expiration dates
2. Call stream_option_chain for "{underlying}" with the nearest expiration, strike_proximity=10
3. Present the chain in a clear table format:
   - Calls on one side, Puts on the other
   - Show Strike, Bid, Ask, Last, Volume, Open Interest
   - Include Delta, IV for each contract
4. Highlight any notable observations (high volume, unusual IV, etc.)"""


@mcp.prompt()
def daily_summary() -> str:
    """Get a complete daily trading summary — balances, orders, positions."""
    return """Provide a complete daily trading summary:
1. Call get_accounts to list all accounts
2. Call get_balances to get current balances
3. Call get_balances_bod to get beginning-of-day balances
4. Call get_orders to get today's orders
5. Call get_positions to get current holdings
6. Present a summary with:
   - Account value: current vs start of day, change
   - Today's orders: fills, pending, cancelled
   - Current positions with unrealized P&L
   - Overall daily P&L"""


# ── Entry point ────────────────────────────────────────────────────


def _register_tools():
    """Initialize clients and register all MCP tools. Called once at startup."""
    ts_client = _init_clients()
    register_market_data_tools(mcp, ts_client)
    register_brokerage_tools(mcp, ts_client)
    register_order_execution_tools(mcp, ts_client)
    logger.info("TradeStation MCP Server initialized with all tools registered.")


def main():
    """Run the TradeStation MCP server."""
    _register_tools()
    mcp.run(transport="stdio")


if __name__ == "__main__":
    main()
