import os
from functools import wraps

from flask import (
    Flask, render_template, redirect, url_for,
    session, request, jsonify
)
from dotenv import load_dotenv

import bot

load_dotenv()

app = Flask(__name__)
app.secret_key = os.getenv('SECRET_KEY', 'change-this-secret')


# ---------------------------------------------------------------------------
# Auth helpers
# ---------------------------------------------------------------------------
def login_required(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        if not session.get('logged_in'):
            return redirect(url_for('login'))
        return f(*args, **kwargs)
    return decorated


# ---------------------------------------------------------------------------
# Auth routes
# ---------------------------------------------------------------------------
@app.route('/')
def index():
    return redirect(url_for('dashboard'))


@app.route('/login', methods=['GET', 'POST'])
def login():
    error = None
    if request.method == 'POST':
        username = request.form.get('username', '').strip()
        password = request.form.get('password', '')
        if (username == os.getenv('DASHBOARD_USERNAME') and
                password == os.getenv('DASHBOARD_PASSWORD')):
            session['logged_in'] = True
            return redirect(url_for('dashboard'))
        error = 'Invalid username or password.'
    return render_template('login.html', error=error)


@app.route('/logout')
def logout():
    session.clear()
    return redirect(url_for('login'))


# ---------------------------------------------------------------------------
# Dashboard
# ---------------------------------------------------------------------------
@app.route('/dashboard')
@login_required
def dashboard():
    paper = os.getenv('PAPER_TRADING', 'true').lower() == 'true'
    return render_template('dashboard.html', paper=paper)


# ---------------------------------------------------------------------------
# API — bot control
# ---------------------------------------------------------------------------
@app.route('/api/bot/start', methods=['POST'])
@login_required
def api_bot_start():
    started = bot.start_bot()
    return jsonify({'started': started, 'running': bot.bot_state['running']})


@app.route('/api/bot/stop', methods=['POST'])
@login_required
def api_bot_stop():
    stopped = bot.stop_bot()
    return jsonify({'stopped': stopped, 'running': bot.bot_state['running']})


# ---------------------------------------------------------------------------
# API — status & account
# ---------------------------------------------------------------------------
@app.route('/api/status')
@login_required
def api_status():
    try:
        api    = bot.get_api()
        acct   = api.get_account()
        clock  = api.get_clock()
        return jsonify({
            'running':       bot.bot_state['running'],
            'market_open':   clock.is_open,
            'next_open':     clock.next_open.isoformat() if not clock.is_open else None,
            'equity':        float(acct.equity),
            'buying_power':  float(acct.buying_power),
            'cash':          float(acct.cash),
            'last_scan':     bot.bot_state['last_scan'],
            'scan_count':    bot.bot_state['scan_count'],
            'paper_trading': os.getenv('PAPER_TRADING', 'true').lower() == 'true',
        })
    except Exception as e:
        return jsonify({'error': str(e)}), 500


# ---------------------------------------------------------------------------
# API — positions
# ---------------------------------------------------------------------------
@app.route('/api/positions')
@login_required
def api_positions():
    try:
        api       = bot.get_api()
        positions = api.list_positions()
        return jsonify([
            {
                'symbol':          p.symbol,
                'qty':             p.qty,
                'avg_entry_price': float(p.avg_entry_price),
                'current_price':   float(p.current_price),
                'market_value':    float(p.market_value),
                'unrealized_pl':   float(p.unrealized_pl),
                'unrealized_plpc': float(p.unrealized_plpc),
                'side':            p.side,
            }
            for p in positions
        ])
    except Exception as e:
        return jsonify({'error': str(e)}), 500


# ---------------------------------------------------------------------------
# AI market outlook (cached — only refreshes every 6 hours)
# ---------------------------------------------------------------------------
_outlook_cache = {'ts': 0, 'data': None}

@app.route('/api/ai_outlook')
@login_required
def api_ai_outlook():
    import time
    from openai import OpenAI

    if time.time() - _outlook_cache['ts'] < 21600 and _outlook_cache['data']:
        return jsonify(_outlook_cache['data'])

    try:
        client = OpenAI(api_key=os.getenv('OPENAI_API_KEY'))
        response = client.chat.completions.create(
            model='gpt-4o-mini',
            messages=[{'role': 'user', 'content':
                """You are a financial analyst. Based on current market conditions, macroeconomic trends,
and typical performance of a diversified portfolio of volatile US stocks (tech, crypto-adjacent, biotech, EV, fintech),
estimate a realistic DAILY return percentage for an algorithmic trading bot over the next 180 trading days.

Be realistic — account for both up and down days. The account starts at $500.

Respond with ONLY this JSON format, no other text:
{"daily_pct": 0.003, "projected_value": 770.00, "projected_gain": 270.00, "sentiment": "Cautiously Bullish"}

Where daily_pct is your estimated avg daily return as a decimal."""
            }],
            max_tokens=80,
            temperature=0.3,
        )
        import json as _json
        text = response.choices[0].message.content.strip()
        data = _json.loads(text)
        _outlook_cache['ts']   = time.time()
        _outlook_cache['data'] = data
        return jsonify(data)
    except Exception as e:
        return jsonify({'error': str(e)}), 500


# ---------------------------------------------------------------------------
# API — daily P&L history
# ---------------------------------------------------------------------------
@app.route('/api/daily_pnl')
@login_required
def api_daily_pnl():
    try:
        api     = bot.get_api()
        history = api.get_portfolio_history(period='1M', timeframe='1D')
        equity  = history.equity
        timestamps = history.timestamp

        days = []
        for i in range(1, len(equity)):
            if equity[i] is None or equity[i-1] is None or equity[i-1] == 0:
                continue
            pnl_dollar = equity[i] - equity[i-1]
            pnl_pct    = pnl_dollar / equity[i-1]
            from datetime import datetime, timezone
            date_str = datetime.fromtimestamp(timestamps[i], tz=timezone.utc).strftime('%b %d')
            days.append({
                'date':       date_str,
                'equity':     round(equity[i], 2),
                'pnl_dollar': round(pnl_dollar, 2),
                'pnl_pct':    round(pnl_pct, 4),
            })

        return jsonify(list(reversed(days[-30:])))
    except Exception as e:
        return jsonify({'error': str(e)}), 500


# ---------------------------------------------------------------------------
# API — trade log
# ---------------------------------------------------------------------------
@app.route('/api/log')
@login_required
def api_log():
    limit = request.args.get('limit', 100, type=int)
    return jsonify(bot.bot_state['trade_log'][:limit])


# ---------------------------------------------------------------------------
# API — watchlist
# ---------------------------------------------------------------------------
@app.route('/api/watchlist', methods=['GET', 'POST'])
@login_required
def api_watchlist():
    if request.method == 'POST':
        data = request.get_json(silent=True) or {}
        raw  = data.get('watchlist', [])
        bot.bot_state['watchlist'] = [s.strip().upper() for s in raw if s.strip()]
        bot._save_watchlist_to_disk(bot.bot_state['watchlist'])
        bot.log_event(f'Watchlist updated: {", ".join(bot.bot_state["watchlist"])}')
    return jsonify({'watchlist': bot.bot_state['watchlist']})


# ---------------------------------------------------------------------------
# Entry point (dev only — use gunicorn in production)
# ---------------------------------------------------------------------------
if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)
