/**
 * Smart Bin Web App (FastAPI Backend)
 *
 * Group Members:
 * Abbas, Mustafa, Aina, Zainab, Asma, Saif
 */

from fastapi import FastAPI, Request                     /** FastAPI core and request support **/
from fastapi.responses import HTMLResponse, JSONResponse /** For returning HTML and JSON data **/
from fastapi.templating import Jinja2Templates           /** For rendering HTML templates **/
import httpx, asyncio                                    /** For async HTTP calls and timing **/

app = FastAPI()                                          /** Create FastAPI app **/
templates = Jinja2Templates(directory="templates")      /** Set up HTML templates folder **/

ARDUINO_URL = "http://192.168.1.35/distance/json"        /** Arduino endpoint for sensor data **/

sensor_data = {                                          /** Cache for latest sensor values **/
    "metal_cm": -1,
    "organic_cm": -1,
    "glass_cm": -1,
    "last_updated": None
}

def classify_bin(distance):
    /** Classify bin level based on distance (cm) **/
    if distance <= 4:
        return "Full"
    elif distance <= 6:
        return "Half"
    elif distance > 6:
        return "Empty"
    else:
        return "Error"

@app.on_event("startup")
async def startup_event():
    /** Start background data fetch loop on server startup **/
    asyncio.create_task(fetch_sensor_data_periodically())

async def fetch_sensor_data_periodically():
    /** Fetch sensor data from Arduino every 60 seconds **/
    global sensor_data
    while True:
        async with httpx.AsyncClient() as client:
            try:
                response = await client.get(ARDUINO_URL, timeout=10)
                data = response.json()
                sensor_data.update(data)
                sensor_data["last_updated"] = asyncio.get_event_loop().time()
                print("Fetched sensor data:", sensor_data)
            except Exception as e:
                print("Failed to fetch sensor data:", e)
        await asyncio.sleep(60)

@app.get("/", response_class=HTMLResponse)
async def read_root(request: Request):
    /** Render HTML dashboard with bin statuses **/
    metal = classify_bin(sensor_data.get("metal_cm", -1))
    organic = classify_bin(sensor_data.get("organic_cm", -1))
    glass = classify_bin(sensor_data.get("glass_cm", -1))

    return templates.TemplateResponse("index.html", {
        "request": request,
        "metal": metal,
        "organic": organic,
        "glass": glass,
        "data": sensor_data
    })

@app.get("/api/status")
async def api_status():
    /** Return bin statuses and raw sensor data as JSON **/
    return {
        "metal_status": classify_bin(sensor_data.get("metal_cm", -1)),
        "organic_status": classify_bin(sensor_data.get("organic_cm", -1)),
        "glass_status": classify_bin(sensor_data.get("glass_cm", -1)),
        "raw": sensor_data
    }
