# main.py
import asyncio
import json
import os
import pathlib
from fastapi import FastAPI, WebSocket, Request
from fastapi.responses import FileResponse, PlainTextResponse, StreamingResponse
from fastapi.staticfiles import StaticFiles
import cv2

# ---------- CONFIG ----------
CAPTURE_EXE = "/home/pi/AI0/main"            # 可执行文件路径
CAPTURE_LOGFILE = "/tmp/capture_stdout.log"  # 用于记录 main 的 stdout
SAMPLE_QUEUE_MAX = 8000
CAMERA_INDEX = 0
STATIC_DIR = "static"  # 你的 index.html 放这里

# ---------- APP ----------
app = FastAPI(title="Glass Adhesive Detection Backend")
app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")

# queue for passing samples to websockets
sample_queue: asyncio.Queue = asyncio.Queue(maxsize=SAMPLE_QUEUE_MAX)

# initialize app.state slots
if not hasattr(app.state, "capture_proc"):
    app.state.capture_proc = None
if not hasattr(app.state, "capture_reader_task"):
    app.state.capture_reader_task = None

# ---------- helper: read proc stdout, push to queue and log ----------
async def _capture_reader_and_log(proc: asyncio.subprocess.Process, logfile_path: str):
    """Read stdout lines from proc, append to logfile, push parsed samples to sample_queue."""
    # ensure log dir exists
    try:
        p = pathlib.Path(logfile_path)
        p.parent.mkdir(parents=True, exist_ok=True)
    except Exception:
        pass

    logf = None
    try:
        logf = open(logfile_path, "ab", buffering=0)
    except Exception as e:
        print("[capture_reader] cannot open log file:", e)
        logf = None

    try:
        assert proc.stdout is not None
        while True:
            line = await proc.stdout.readline()
            if not line:
                break  # EOF
            # write raw bytes to logfile
            try:
                if logf:
                    if isinstance(line, bytes):
                        logf.write(line if line.endswith(b"\n") else line + b"\n")
                    else:
                        logf.write(str(line).encode("utf-8", errors="ignore") + b"\n")
            except Exception:
                pass

            # normalize to string
            try:
                if isinstance(line, bytes):
                    s = line.decode("utf-8", errors="ignore").strip()
                else:
                    s = str(line).strip()
            except Exception:
                s = None

            if not s:
                continue

            # Expect CSV line: t,volt,accel_g,accel_mps2
            parts = s.split(",")
            if len(parts) != 4:
                # skip info lines
                continue
            try:
                sample = {
                    "t": float(parts[0]),
                    "volt": float(parts[1]),
                    "accel_g": float(parts[2]),
                    "accel_mps2": float(parts[3])
                }
            except Exception as e:
                # parse error - skip
                print("[capture_reader] parse error:", e, "line:", s)
                continue

            # push into queue (drop-oldest policy if full)
            try:
                sample_queue.put_nowait(sample)
            except asyncio.QueueFull:
                try:
                    _ = sample_queue.get_nowait()
                    sample_queue.put_nowait(sample)
                except Exception:
                    pass
    except asyncio.CancelledError:
        # task cancelled: exit cleanly
        raise
    except Exception as e:
        print("[capture_reader] exception:", e)
    finally:
        try:
            if logf:
                logf.close()
        except Exception:
            pass

# ---------- start capture ----------
@app.post("/start_capture")
async def start_capture(req: Request):
    # if already running, return status
    proc = getattr(app.state, "capture_proc", None)
    if proc is not None:
        rc = getattr(proc, "returncode", None)
        if rc is None:
            return {"status": "already_running", "pid": getattr(proc, "pid", None)}
        else:
            # cleaned up previously
            app.state.capture_proc = None

    # check executable
    if not os.path.isfile(CAPTURE_EXE) or not os.access(CAPTURE_EXE, os.X_OK):
        return {"status": "failed", "reason": f"executable missing or not executable: {CAPTURE_EXE}"}

    # clear logfile
    try:
        open(CAPTURE_LOGFILE, "wb").close()
    except Exception:
        pass

    # start async subprocess
    proc = await asyncio.create_subprocess_exec(
        CAPTURE_EXE,
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.STDOUT
    )
    app.state.capture_proc = proc

    # start reader task
    reader_task = asyncio.create_task(_capture_reader_and_log(proc, CAPTURE_LOGFILE))
    app.state.capture_reader_task = reader_task

    # monitor to cleanup when process exits
    async def _monitor():
