# /var/www/html/backtestingmarket/admin_service.py
from flask import Blueprint, jsonify, request
import subprocess
import os
from flask_login import current_user
import json

admin_bp = Blueprint("admin_bp", __name__, url_prefix="/admin/api")

# --- Servicios que queremos controlar ---
SERVICES = {
    "allchain": {
        "name": "btm-allchain.service",
        "log": "/var/www/html/logs/allchainIV_V2.log",
    },
    "outliers": {
        "name": "btm-outliers.service",
        "log": "/var/www/html/logs/gettingChains_outliers4.log",
    },
    "tokenrefresh": {
        "name": "btm-tokenrefresh.service",
        "log": "/var/www/html/logs/tokenrefresh.log",
    },
    "predictor": {
        "name": "btm-predictor.service",
        "log": "/var/www/html/logs/predictor.log",
    }
}

PREDICTOR_LOG_DIR = "/var/www/html/logs"
PREDICTOR_SYMBOLS = {"SPX", "RUT", "QQQ", "SPY", "XSP"}

def get_allowed_emails():
    """
    Lee ADMIN_ALLOWED_EMAILS del entorno EN EL MOMENTO DEL REQUEST.
    Soporta lista separada por comas.
    """
    raw = os.getenv("ADMIN_ALLOWED_EMAILS", "")
    return {
        e.strip().lower()
        for e in raw.split(",")
        if e.strip()
    }


@admin_bp.before_request
def restrict_admin_api():
    """Restringe el acceso al API solo a usuarios logueados y whitelisted."""
    if not current_user.is_authenticated:
        return jsonify({"ok": False, "error": "forbidden"}), 403

    email = (getattr(current_user, "email", "") or "").lower()
    allowed = get_allowed_emails()

    # Si la lista está vacía, por seguridad NO dejamos pasar a nadie
    if not allowed:
        return jsonify({"ok": False, "error": "forbidden"}), 403

    if email not in allowed:
        return jsonify({"ok": False, "error": "forbidden"}), 403


# --- Helpers ---
def run_cmd(cmd):
    """Ejecuta un comando y devuelve (returncode, output)."""
    res = subprocess.run(cmd, capture_output=True, text=True)
    return res.returncode, res.stdout + res.stderr


def tail_log(path, n=100):
    """Devuelve las últimas n líneas de un archivo de log."""
    if not os.path.exists(path):
        return None
    with open(path, "rb") as f:
        f.seek(0, os.SEEK_END)
        size = f.tell()
        block = 4096
        data = b""
        while size > 0 and data.count(b"\n") <= n:
            step = min(block, size)
            size -= step
            f.seek(size)
            data = f.read(step) + data
    return data.decode("utf-8", errors="replace").splitlines()[-n:]


# --- Rutas dinámicas para cada servicio ---
SYSTEMCTL = "/usr/bin/systemctl"  # ← ruta que habilitaste en sudoers


@admin_bp.route("/<service>/start", methods=["POST"])
def start_service(service):
    if service not in SERVICES:
        return jsonify({"ok": False, "error": "unknown service"}), 404
    code, out = run_cmd(["sudo", SYSTEMCTL, "start", SERVICES[service]["name"]])
    return jsonify({"ok": code == 0, "output": out})


@admin_bp.route("/<service>/stop", methods=["POST"])
def stop_service(service):
    if service not in SERVICES:
        return jsonify({"ok": False, "error": "unknown service"}), 404
    code, out = run_cmd(["sudo", SYSTEMCTL, "stop", SERVICES[service]["name"]])
    return jsonify({"ok": code == 0, "output": out})


@admin_bp.route("/<service>/status", methods=["GET"])
def status_service(service):
    if service not in SERVICES:
        return jsonify({"ok": False, "error": "unknown service"}), 404
    svc_name = SERVICES[service]["name"]

    # Estado simple
    code1, out1 = run_cmd([SYSTEMCTL, "is-active", svc_name])
    # Detalle útil
    code2, out2 = run_cmd([
        SYSTEMCTL, "show", svc_name,
        "--property=ActiveState,SubState,MainPID,ExecMainStatus",
        "--no-pager"
    ])
    return jsonify({
        "ok": code1 == 0,
        "is_active": out1.strip(),
        "details": out2
    })


@admin_bp.route("/<service>/logs", methods=["GET"])
def logs_service(service):
    if service not in SERVICES:
        return jsonify({"ok": False, "error": "unknown service"}), 404

    n = int(request.args.get("n", 100))  # por defecto últimas 100 líneas

    # Caso especial: predictor → 5 logs (uno por símbolo)
    if service == "predictor":
        symbol = request.args.get("symbol", "SPX").replace("$", "").upper()
        if symbol not in PREDICTOR_SYMBOLS:
            return jsonify({"ok": False, "error": "invalid symbol"}), 400

        log_path = os.path.join(PREDICTOR_LOG_DIR, f"pred_{symbol}.log")
    else:
        # Comportamiento normal para el resto de servicios
        log_path = SERVICES[service]["log"]

    lines = tail_log(log_path, n)
    if lines is None:
        return jsonify({"ok": False, "error": "Log file not found"}), 404

    return jsonify({"ok": True, "lines": lines})



@admin_bp.route("/token/status", methods=["GET"])
def token_status():
    path = "/var/www/tokens_schwab/tokens.json"
    if not os.path.exists(path):
        return jsonify({"ok": False, "error": "tokens.json not found"}), 404

    try:
        with open(path) as f:
            data = json.load(f)
    except Exception as e:
        return jsonify({"ok": False, "error": str(e)}), 500

    import datetime

    now = datetime.datetime.now(datetime.timezone.utc)
    at_issued = datetime.datetime.fromisoformat(data["access_token_issued"])
    rt_issued = datetime.datetime.fromisoformat(data["refresh_token_issued"])

    ACCESS_TIMEOUT = 1800        # 30 min
    REFRESH_TIMEOUT = 7 * 86400  # 7 days

    at_expire = at_issued + datetime.timedelta(seconds=ACCESS_TIMEOUT)
    rt_expire = rt_issued + datetime.timedelta(seconds=REFRESH_TIMEOUT)

    return jsonify({
        "ok": True,
        "access_expires_in": (at_expire - now).total_seconds(),
        "refresh_expires_in": (rt_expire - now).total_seconds(),
        "access_expires_at": at_expire.isoformat(),
        "refresh_expires_at": rt_expire.isoformat()
    })
