#!/usr/bin/env python3
import json
import sqlite3
import time
from pathlib import Path

from flask import Flask, render_template, Response, jsonify, request

INSTANCE_NAME = "Steve0"
DB_FILE = Path("/var/www/html/logs/ocpp-monitor-steve0/ocpp_logs.db")
PORT = 5001

app = Flask(__name__)

def get_db():
    conn = sqlite3.connect(DB_FILE, timeout=30)
    conn.execute("PRAGMA busy_timeout=30000")
    conn.row_factory = sqlite3.Row
    return conn

@app.route("/")
def index():
    return render_template("index.html", instance=INSTANCE_NAME)

@app.route("/api/messages")
def get_messages():
    chargebox = request.args.get("chargebox", "")
    action = request.args.get("action", "")
    direction = request.args.get("direction", "")

    conn = get_db()
    query = "SELECT * FROM ocpp_messages WHERE 1=1"
    params = []

    if chargebox:
        query += " AND chargebox_id = ?"
        params.append(chargebox)

    if action:
        query += " AND (action = ? OR action = ?)"
        params.extend([action, f"↳ {action}"])

    if direction:
        query += " AND direction = ?"
        params.append(direction)

    query += " ORDER BY id DESC"

    rows = conn.execute(query, params).fetchall()
    conn.close()

    return jsonify([dict(row) for row in rows])

@app.route("/api/conversation/<message_id>")
def get_conversation(message_id):
    conn = get_db()
    rows = conn.execute(
        "SELECT * FROM ocpp_messages WHERE message_id = ? ORDER BY id",
        (message_id,)
    ).fetchall()
    conn.close()
    return jsonify([dict(row) for row in rows])

@app.route("/api/chargeboxes")
def get_chargeboxes():
    conn = get_db()
    rows = conn.execute(
        "SELECT DISTINCT chargebox_id FROM ocpp_messages ORDER BY chargebox_id"
    ).fetchall()
    conn.close()
    return jsonify([r["chargebox_id"] for r in rows])

@app.route("/api/actions")
def get_actions():
    conn = get_db()
    rows = conn.execute(
        "SELECT DISTINCT action FROM ocpp_messages WHERE action IS NOT NULL ORDER BY action"
    ).fetchall()
    conn.close()

    unique_actions = set()
    for r in rows:
        action = r["action"]
        if action:
            if action.startswith("↳ "):
                unique_actions.add(action[2:])
            else:
                unique_actions.add(action)

    return jsonify(sorted(unique_actions))

@app.route("/api/stats")
def get_stats():
    conn = get_db()
    stats = {}

    stats["instance"] = INSTANCE_NAME
    stats["total"] = conn.execute("SELECT COUNT(*) FROM ocpp_messages").fetchone()[0]
    stats["last_hour"] = conn.execute(
        "SELECT COUNT(*) FROM ocpp_messages WHERE created_at > datetime('now', '-1 hour')"
    ).fetchone()[0]
    stats["chargeboxes"] = conn.execute(
        "SELECT COUNT(DISTINCT chargebox_id) FROM ocpp_messages"
    ).fetchone()[0]
    stats["errors"] = conn.execute(
        "SELECT COUNT(*) FROM ocpp_messages WHERE message_type = 'CALLERROR'"
    ).fetchone()[0]

    conn.close()
    return jsonify(stats)

@app.route("/stream")
def stream():
    last_id = request.args.get("last_id", 0, type=int)

    def event_generator():
        nonlocal last_id
        conn = get_db()
        while True:
            rows = conn.execute(
                "SELECT * FROM ocpp_messages WHERE id > ? ORDER BY id",
                (last_id,)
            ).fetchall()

            for row in rows:
                last_id = row["id"]
                data = dict(row)
                data["payload_pretty"] = json.dumps(
                    json.loads(data["payload"]), indent=2, ensure_ascii=False
                ) if data["payload"] else ""

                yield f"data: {json.dumps(data)}\n\n"

            time.sleep(0.5)

    return Response(
        event_generator(),
        mimetype="text/event-stream",
        headers={
            "Cache-Control": "no-cache",
            "X-Accel-Buffering": "no"
        }
    )

if __name__ == "__main__":
    print(f"Demarrage du serveur OCPP Monitor - {INSTANCE_NAME}")
    print(f"Acces: http://localhost:{PORT}")
    app.run(host="0.0.0.0", port=PORT, debug=False, threaded=True)

