"""
Flask web panel for the Tabdeal Trading Bot.
Run with: python webapp/app.py
"""
import json
import math
import os
import sys

sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

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

load_dotenv()

from webapp.auth import check_password, login_required, PANEL_USERNAME
from webapp import bot_controller as bc

app = Flask(__name__, template_folder="templates", static_folder="static")
app.secret_key = os.getenv("FLASK_SECRET_KEY", os.urandom(24).hex())


# ------------------------------------------------------------------ #
#  Auth routes                                                         #
# ------------------------------------------------------------------ #

@app.route("/login", methods=["GET", "POST"])
def login():
    error = None
    if request.method == "POST":
        username = request.form.get("username", "")
        password = request.form.get("password", "")
        if username == PANEL_USERNAME and check_password(password):
            session["logged_in"] = True
            session.permanent = True
            next_url = request.args.get("next", "/")
            return redirect(next_url)
        error = "نام کاربری یا رمز عبور اشتباه است"
    return render_template("login.html", error=error)


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


# ------------------------------------------------------------------ #
#  Main dashboard                                                      #
# ------------------------------------------------------------------ #

@app.route("/")
@login_required
def index():
    return render_template("dashboard.html")


# ------------------------------------------------------------------ #
#  API: bot status & control                                           #
# ------------------------------------------------------------------ #

@app.route("/api/status")
@login_required
def api_status():
    state = bc.get_state()
    trades = bc.get_trades()
    running = bc.is_running()

    closed = [t for t in trades if t.get("status") == "CLOSED"]
    wins = [t for t in closed if t.get("result") == "WIN"]
    losses = [t for t in closed if t.get("result") == "LOSS"]
    net_pnls = [t.get("net_pnl", 0) or 0 for t in closed]
    total_pnl = sum(net_pnls)
    win_rate = len(wins) / len(closed) * 100 if closed else 0

    avg_win = sum(t.get("net_pnl", 0) or 0 for t in wins) / len(wins) if wins else 0
    avg_loss = abs(sum(t.get("net_pnl", 0) or 0 for t in losses)) / len(losses) if losses else 0
    gross_win = len(wins) * avg_win
    gross_loss = len(losses) * avg_loss
    profit_factor = gross_win / gross_loss if gross_loss > 0 else None

    # Max drawdown
    running_sum = 0.0
    peak = 0.0
    max_dd = 0.0
    for p in net_pnls:
        running_sum += p
        if running_sum > peak:
            peak = running_sum
        dd = peak - running_sum
        if dd > max_dd:
            max_dd = dd

    # Sharpe
    sharpe = 0.0
    if len(net_pnls) > 1:
        mean_r = total_pnl / len(net_pnls)
        var = sum((r - mean_r) ** 2 for r in net_pnls) / len(net_pnls)
        std = math.sqrt(var)
        sharpe = mean_r / std if std > 0 else 0.0

    # Open trade
    open_trades = [t for t in trades if t.get("status") == "OPEN"]

    return jsonify({
        "running": running,
        "demo_mode": os.getenv("DEMO_MODE", "true").lower() == "true",
        "state": state,
        "stats": {
            "total_trades": len(closed),
            "wins": len(wins),
            "losses": len(losses),
            "win_rate": round(win_rate, 1),
            "total_pnl": round(total_pnl, 4),
            "avg_win": round(avg_win, 4),
            "avg_loss": round(avg_loss, 4),
            "profit_factor": round(profit_factor, 3) if profit_factor else None,
            "max_drawdown": round(max_dd, 4),
            "sharpe": round(sharpe, 3),
            "daily_pnl": state.get("daily_pnl", 0),
            "total_pnl_state": state.get("total_pnl", 0),
        },
        "open_trade": open_trades[-1] if open_trades else None,
    })


@app.route("/api/trades")
@login_required
def api_trades():
    trades = bc.get_trades()
    page = int(request.args.get("page", 1))
    per_page = int(request.args.get("per_page", 20))
    start = (page - 1) * per_page
    end = start + per_page
    closed = list(reversed([t for t in trades if t.get("status") == "CLOSED"]))
    return jsonify({
        "trades": closed[start:end],
        "total": len(closed),
        "page": page,
        "pages": math.ceil(len(closed) / per_page) if closed else 1,
    })


@app.route("/api/logs")
@login_required
def api_logs():
    lines = int(request.args.get("lines", 80))
    return jsonify({"lines": bc.get_log_tail(lines)})


@app.route("/api/bot/start", methods=["POST"])
@login_required
def api_start():
    demo = request.json.get("demo", True) if request.is_json else True
    result = bc.start_bot(demo=demo)
    return jsonify(result)


@app.route("/api/bot/stop", methods=["POST"])
@login_required
def api_stop():
    result = bc.stop_bot()
    return jsonify(result)


# ------------------------------------------------------------------ #
#  API: config                                                         #
# ------------------------------------------------------------------ #

@app.route("/api/config", methods=["GET"])
@login_required
def api_config_get():
    return jsonify(bc.get_config_override())


@app.route("/api/config", methods=["POST"])
@login_required
def api_config_save():
    data = request.get_json(force=True) or {}
    bc.save_config_override(data)
    return jsonify({"ok": True})


# ------------------------------------------------------------------ #
#  Run                                                                 #
# ------------------------------------------------------------------ #

if __name__ == "__main__":
    port = int(os.getenv("PANEL_PORT", 5000))
    debug = os.getenv("FLASK_DEBUG", "false").lower() == "true"
    app.run(host="0.0.0.0", port=port, debug=debug)
