import streamlit as st
import yaml
import subprocess
import os
import time
import signal
import web_status 
import psutil
from pathlib import Path

# --- 1. CONFIGURAZIONE PAGINA ---
st.set_page_config(
    page_title="BLE Localizer Manager",
    layout="wide",
    initial_sidebar_state="auto"
)

# --- 2. CONFIGURAZIONE PERCORSI E STATI PERSISTENTI ---
REAL_CONFIG_PATH = "/config/config.yaml" if os.path.exists("/config/config.yaml") else "/app/config/config.yaml"
LOG_FILE = "/tmp/main_process.log"

# File di stato su disco per la persistenza
CORE_STATE_FILE = "/data/config/core.enabled"
LOG_PID_FILE = "/tmp/mqtt_logging.pid"

def load_yaml(path):
    if not os.path.exists(path): return {}
    with open(path, 'r', encoding='utf-8') as f: return yaml.safe_load(f) or {}

def save_yaml(path, data):
    with open(path, 'w', encoding='utf-8') as f: yaml.dump(data, f, default_flow_style=False)

cfg = load_yaml(REAL_CONFIG_PATH)

# --- 3. LOGICA PERSISTENZA CORE ---
def stop_core_engine():
    """Arresta il core e rimuove il flag di persistenza."""
    if os.path.exists(CORE_STATE_FILE): 
        os.remove(CORE_STATE_FILE)
        
    for proc in psutil.process_iter(['cmdline']):
        try:
            cmd = proc.info['cmdline']
            if cmd and ('app.main' in ' '.join(cmd) or 'main.py' in ' '.join(cmd)):
                proc.terminate()
                proc.wait(timeout=2)
        except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.TimeoutExpired):
            try: proc.kill()
            except: pass

def start_core_engine():
    """Avvia il core e crea il flag di persistenza su disco."""
    Path(CORE_STATE_FILE).touch()
    env = os.environ.copy()
    env["CONFIG"] = REAL_CONFIG_PATH 
    env["PYTHONPATH"] = "/app"
    # Reindirizzamento append log per non perdere lo storico dell'entrypoint
    with open(LOG_FILE, "a") as log_f:
        subprocess.Popen(
            ["python3", "-m", "app.main"],
            env=env,
            cwd="/app",
            stdout=log_f,
            stderr=log_f,
            start_new_session=True
        )

# --- 4. MONITORAGGIO ATTIVO (SENZA AUTO-START BLOCCANTE) ---
# La logica di avvio al boot è ora gestita da entrypoint.sh.
# Qui segnaliamo solo se lo stato desiderato (file esistente) non coincide con quello reale.
if os.path.exists(CORE_STATE_FILE) and not web_status.is_main_running():
    st.sidebar.warning("⚠️ Core abilitato ma non in esecuzione.")
    if st.sidebar.button("RIPRISTINA ORA"):
        start_core_engine()
        st.rerun()

# --- 5. TITOLO E LOGIN ---
st.title("🛰️ BLE AI Localizer - Suite")

if "password_correct" not in st.session_state:
    st.session_state["password_correct"] = False

if not st.session_state["password_correct"]:
    user = st.text_input("Username")
    pw = st.text_input("Password", type="password")
    if st.button("ACCEDI"):
        if user == os.environ.get("UI_USER", "admin") and pw == os.environ.get("UI_PASSWORD", "password"):
            st.session_state["password_correct"] = True
            st.rerun()
        else:
            st.error("Credenziali errate")
    st.stop()

# --- 6. SIDEBAR: CONTROLLI SISTEMA ---
with st.sidebar:
    st.header("🛠️ Core Control")
    
    is_running = web_status.is_main_running()
    st.markdown(f"STATO: {':green[**CORE ATTIVO**]' if is_running else ':red[**CORE FERMO**]'}")
    
    if st.button("🚀 RIAVVIA CORE" if is_running else "▶️ AVVIA CORE", use_container_width=True):
        stop_core_engine()
        time.sleep(1)
        start_core_engine()
        st.rerun()

    st.divider()
    
    # --- GESTIONE MQTT RAW PERSISTENTE ---
    is_logging_active = False
    if os.path.exists(LOG_PID_FILE):
        try:
            with open(LOG_PID_FILE, "r") as f:
                saved_pid = int(f.read().strip())
            if psutil.pid_exists(saved_pid):
                is_logging_active = True
            else:
                os.remove(LOG_PID_FILE)
        except:
            pass

    raw_active = st.toggle("🔴 MQTT RAW RECORDING", value=is_logging_active)
    
    if raw_active and not is_logging_active:
        RAW_LOG_DIR = cfg.get('paths', {}).get('mqtt_raw_dir', '/data/mqtt_raw/')
        os.makedirs(RAW_LOG_DIR, exist_ok=True)
        dt = time.strftime("%Y%m%d_%H%M%S")
        filepath = os.path.join(RAW_LOG_DIR, f"mqtt_raw_{dt}.log")
        m_cfg = cfg.get('mqtt', {})
        m_filter = m_cfg.get('topic', 'publish_out').split('/')[0]
        
        cmd = f"stdbuf -oL mosquitto_sub -v -h {m_cfg.get('host')} -p {m_cfg.get('port')} -t '#' | stdbuf -oL grep '{m_filter}' > {filepath}"
        proc = subprocess.Popen(cmd, shell=True, preexec_fn=os.setsid)
        
        with open(LOG_PID_FILE, "w") as f:
            f.write(str(proc.pid))
        st.rerun()
    
    elif not raw_active and is_logging_active:
        try: 
            with open(LOG_PID_FILE, "r") as f:
                pid_to_kill = int(f.read().strip())
            os.killpg(os.getpgid(pid_to_kill), signal.SIGTERM)
            if os.path.exists(LOG_PID_FILE): os.remove(LOG_PID_FILE)
            st.rerun()
        except: 
            pass

# --- 7. IMPORT MODULI E TABS ---
from map_manager import show_mapper
from web_gateway import show_gateway_manager
from web_beacon import show_beacon_manager
from web_test_inference import show_test_inference
import web_training_data
import web_inference

tab_log, tab_cfg, tab_sec, tab_gw, tab_beac, tab_map, tab_model, tab_infer_test, tab_infer, tab_status = st.tabs([
    "📜 Log", "⚙️ Config", "🔑 Secrets", "🌐 Gateway", "🏷️ Beacon", "📍 Rilevamento", "🧠 Modello", "🧪 InferTest", "🤖 Inferenza", "🖥️ Stato"
])

with tab_log:
    col_l1, col_l2 = st.columns(2)
    if col_l1.button("🔄 AGGIORNA LOG", use_container_width=True): st.rerun()
    if col_l2.button("🗑️ AZZERA LOG", use_container_width=True):
        try:
            with open(LOG_FILE, "w") as f: f.write(f"--- Log resettato il {time.strftime('%Y-%m-%d %H:%M:%S')} ---\n")
            st.success("Log azzerato!"); time.sleep(1); st.rerun()
        except: st.error("Errore pulizia log")
    if os.path.exists(LOG_FILE):
        with open(LOG_FILE, "r") as f: st.code("".join(f.readlines()[-100:]))

with tab_cfg:
    st.subheader("🚀 Configurazione Operativa")
    cfg_text = st.text_area("Expert Mode (YAML)", yaml.dump(cfg), height=400)
    if st.button("💾 SALVA CONFIG"):
        save_yaml(REAL_CONFIG_PATH, yaml.safe_load(cfg_text)); st.success("Salvato!")

with tab_sec:
    CURR_SECRETS = os.environ.get("SECRETS_FILE") or "/config/secrets.yaml"
    sec = load_yaml(CURR_SECRETS)
    sec_edit = st.text_area("Secrets YAML", yaml.dump(sec), height=200)
    if st.button("SALVA SECRETS"): 
        save_yaml(CURR_SECRETS, yaml.safe_load(sec_edit)); st.success("OK!")

with tab_gw: show_gateway_manager(cfg)
with tab_beac: show_beacon_manager(cfg)
with tab_map: show_mapper(cfg)
with tab_model: web_training_data.show_training_data_manager(cfg)
with tab_infer_test: show_test_inference(cfg) 
with tab_infer: web_inference.show_inference_page(cfg)
with tab_status:
    sec_data = load_yaml(os.environ.get("SECRETS_FILE") or "/config/secrets.yaml")
    web_status.show_system_status(cfg, sec_data)
