#!/usr/bin/env python3
"""
Glass Curtain Wall Adhesive Detection System
FastAPI + OpenCV (Camera MJPEG) + CSV Tail + WebSocket
"""
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import StreamingResponse, FileResponse
from fastapi.staticfiles import StaticFiles
import asyncio, threading, time, glob, os, json, cv2, numpy as np

# ==================== CONFIG ====================
CSV_DIR = "/home/pi/acc_data"
CSV_GLOB = "ai0_accel_*.csv"
POLL_INTERVAL = 0.05
CAMERA_INDEX = 0    # USB camera index (/dev/video0)
# =================================================

app = FastAPI(title="玻璃幕墙结构胶检测系统")

# Static files
app.mount("/static", StaticFiles(directory="static"), name="static")

@app.get("/")
def index():
    """Return main page"""
    return FileResponse(os.path.join("static", "index.html"))

# ========== CSV 文件实时监控 ==========
data_queue: asyncio.Queue = asyncio.Queue(maxsize=5000)

def find_latest_csv():
    files = glob.glob(os.path.join(CSV_DIR, CSV_GLOB))
    if not files:
        return None
    files.sort(key=os.path.getmtime, reverse=True)
    return files[0]

def tail_file(path, loop, queue: asyncio.Queue, stop_event: threading.Event):
    """持续读取 CSV 新行并推送入队"""
    try:
        f = open(path, "r", encoding="utf-8", errors="ignore")
    except Exception as e:
        print("打开 CSV 失败:", e)
        return
    f.seek(0, os.SEEK_END)
    print(f"[tail_file] 读取文件: {path}")
    while not stop_event.is_set():
        line = f.readline()
        if not line:
            time.sleep(POLL_INTERVAL)
            continue
        parts = [p.strip() for p in line.split(",") if p.strip()]
        if len(parts) < 4:
            continue
        try:
            t, volt, acc_g, acc_ms2 = map(float, parts[:4])
            sample = {"t": t, "volt": volt, "accel_g": acc_g, "accel_mps2": acc_ms2}
            loop.call_soon_threadsafe(asyncio.create_task, queue.put(sample))
        except Exception as e:
            print("解析行失败:", e)
            continue
    f.close()
    print("[tail_file] 文件读取结束")

async def csv_watcher():
    stop_event = None
    tail_thread = None
    current_file = None
    loop = asyncio.get_event_loop()
    while True:
        latest = find_latest_csv()
        if latest != current_file:
            if tail_thread and stop_event:
                stop_event.set()
                tail_thread.join(timeout=1)
            current_file = latest
            if current_file:
                stop_event = threading.Event()
                tail_thread = threading.Thread(target=tail_file, args=(current_file, loop, data_queue, stop_event), daemon=True)
                tail_thread.start()
                print("[csv_watcher] 正在读取:", current_file)
            else:
                print("[csv_watcher] 未找到 CSV 文件")
        await asyncio.sleep(1.0)

@app.on_event("startup")
async def startup_event():
    asyncio.create_task(csv_watcher())
    print("系统启动完成，监测目录:", CSV_DIR)

# ========== WebSocket 通信 ==========
@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    print("WebSocket 客户端连接:", websocket.client)
    try:
        while True:
            data = await data_queue.get()
            await websocket.send_text(json.dumps(data, ensure_ascii=False))
    except WebSocketDisconnect:
        print("客户端断开:", websocket.client)

# ========== 摄像头 MJPEG 流 ==========
def gen_frames():
    cap = cv2.VideoCapture(CAMERA_INDEX)
    if not cap.isOpened():
        print("[Camera] 无法打开摄像头")
        return
    while True:
        ret, frame = cap.read()
        if not ret:
            time.sleep(0.1)
            continue
        ret, buffer = cv2.imencode('.jpg', frame)
        if not ret:
            continue
        frame_bytes = buffer.tobytes()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame_bytes + b'\r\n')
    cap.release()

@app.get("/video_feed")
def video_feed():
    """MJPEG视频流接口"""
    return StreamingResponse(gen_frames(), media_type='multipart/x-mixed-replace; boundary=frame')
