# app.py
import streamlit as st
import ollama
import json
import subprocess
import time
import os

CMD_FILE = "/tmp/led_cmd.json"

# =========================================================
# 基本設定
# =========================================================
st.set_page_config(
    page_title="工業儀表板 · LLM 燈號控制",
    layout="wide"
)

os.environ["OLLAMA_NUM_GPU"] = "1"

# =========================================================
# CSS（科技感工業風）
# =========================================================
st.markdown("""
<style>
body { background-color:#020617; }
.dashboard {
    display:grid;
    grid-template-columns:repeat(6,1fr);
    gap:14px;
    margin-bottom:1rem;
}
.card {
    background:linear-gradient(145deg,#020617,#020617);
    border:1px solid #1e293b;
    border-radius:14px;
    padding:14px 10px;
    text-align:center;
}
.card h4 {
    margin:0;
    font-size:0.9rem;
    color:#94a3b8;
}
.card .value {
    font-size:2.1rem;
    font-weight:800;
    color:#e5e7eb;
}
.card .sub {
    font-size:0.8rem;
    color:#64748b;
}
.warn {
    background:linear-gradient(145deg,#450a0a,#020617);
    border-color:#dc2626;
}
</style>
""", unsafe_allow_html=True)

# =========================================================
# 標題
# =========================================================
st.markdown(
    "<h2 style='color:#e5e7eb;margin-bottom:0.8rem'>🧠 工業儀表板 · LLM 燈號控制</h2>",
    unsafe_allow_html=True
)

# =========================================================
# 系統工具
# =========================================================
def run(cmd):
    return subprocess.check_output(cmd, shell=True, text=True).strip()

def cpu_usage():
    idle = run(
        "top -bn1 | grep 'Cpu(s)' | sed 's/,/ /g' | "
        "awk '{for(i=1;i<=NF;i++) if ($i==\"id\") print $(i-1)}'"
    )
    return 100 - float(idle)

def ram_usage():
    _, _, p = run("free -m | awk 'NR==2{print $3,$2,$3/$2*100}'").split()
    return float(p)

def swap_usage():
    _, _, p = run("free -m | awk 'NR==3{print $3,$2,($3/$2)*100}'").split()
    return float(p)

def disk_usage():
    _, _, p = run("df -h / | awk 'NR==2{print $3,$2,$5}'").split()
    return p

def cpu_temp():
    return float(run("vcgencmd measure_temp | cut -d= -f2 | tr -d \"'C\""))

def net_usage():
    iface = run(
        "ip -o link show | awk -F': ' '{print $2}' | "
        "grep -E '^(eth|wlan|usb)' | head -n1"
    )
    rx, tx = run(
        f"cat /proc/net/dev | grep {iface} | awk '{{print $2,$10}}'"
    ).split()
    return iface, int(tx)//1024**2, int(rx)//1024**2

# =========================================================
# LLM + fallback（現場保命）
# =========================================================
def analyze(text):
    try:
        r = ollama.chat(
            model="llama3.2:3b",
            messages=[
                {
                    "role": "system",
                    "content": (
                        "只輸出 JSON："
                        '{"color":"red","action":"on"},'
                        '{"color":"red","action":"off"},'
                        '{"color":"green","action":"on"},'
                        '{"color":"green","action":"off"},'
                        '{"color":"all","action":"on"},'
                        '{"color":"all","action":"off"}'
                    )
                },
                {"role": "user", "content": text}
            ],
            options={"temperature": 0, "num_predict": 20}
        )
        return json.loads(r["message"]["content"])
    except:
        return fallback(text)

def fallback(text):
    if "紅" in text and "開" in text:
        return {"color":"red","action":"on"}
    if "紅" in text and "關" in text:
        return {"color":"red","action":"off"}
    if "綠" in text and "開" in text:
        return {"color":"green","action":"on"}
    if "綠" in text and "關" in text:
        return {"color":"green","action":"off"}
    if "全部" in text and "開" in text:
        return {"color":"all","action":"on"}
    if "全部" in text and "關" in text:
        return {"color":"all","action":"off"}
    return None

def send_cmd(cmd):
    tmp = CMD_FILE + ".tmp"
    with open(tmp, "w") as f:
        json.dump(cmd, f)
        f.flush()
        os.fsync(f.fileno())
    os.replace(tmp, CMD_FILE)

# =========================================================
# 取得監控數據
# =========================================================
cpu  = cpu_usage()
ram  = ram_usage()
swap = swap_usage()
disk = disk_usage()
temp = cpu_temp()
iface, tx, rx = net_usage()

# =========================================================
# 儀表板顯示
# =========================================================
st.markdown(f"""
<div class="dashboard">
  <div class="card"><h4>CPU</h4><div class="value">{cpu:.0f}%</div></div>
  <div class="card"><h4>RAM</h4><div class="value">{ram:.0f}%</div></div>
  <div class="card"><h4>SWAP</h4><div class="value">{swap:.0f}%</div></div>
  <div class="card"><h4>DISK</h4><div class="value">{disk}</div></div>
  <div class="card {'warn' if temp>=80 else ''}">
      <h4>TEMP</h4><div class="value">{temp:.1f}°C</div>
  </div>
  <div class="card">
      <h4>NET</h4>
      <div class="value">{iface}</div>
      <div class="sub">↑{tx} ↓{rx} MB</div>
  </div>
</div>
""", unsafe_allow_html=True)

# =========================================================
# 燈號控制
# =========================================================
st.subheader("💡 燈號控制")
cmd = st.text_input("中文指令（例：開紅燈 / 關綠燈 / 全部關）")

if st.button("送出指令"):
    result = analyze(cmd)
    if result:
        send_cmd(result)
        st.success(f"已送出：{result}")
    else:
        st.error("無法解析指令")

# =========================================================
# 過熱硬保護
# =========================================================
if temp >= 85:
    send_cmd({"color":"all","action":"off"})
    st.error("⚠️ CPU 過熱，已強制關燈")

# =========================================================
# 自動刷新
# =========================================================
time.sleep(3)
st.rerun()