from flask import Flask, render_template, jsonify, request, abort
from datetime import datetime, timedelta
from pathlib import Path
import requests
import struct
import csv
import os

app = Flask(__name__)

# ====== KONFIGURACE ======
DATA_DIR = Path(os.environ.get("HIST_CSV_DIR", "/opt/mbm/logs"))  # složka s denními CSV (DD_MM_RR.csv)
MODBUS_API_URL = os.environ.get("MODBUS_API_URL", "http://localhost/modbus/call")
API_KEY = os.environ.get("MODBUS_API_KEY", "tajny-klic")


# ========= POMOCNÉ FUNKCE =========
def ensure_list(value):
    if isinstance(value, list):
        return value
    elif value is None:
        return []
    else:
        return [value]


def call_modbus(payload: dict):
    """Volání tvého /modbus/call API (X-API-Key)."""
    try:
        resp = requests.post(
            MODBUS_API_URL,
            json=payload,
            headers={"X-API-Key": API_KEY, "Content-Type": "application/json"},
            timeout=5,
        )
        resp.raise_for_status()
        return resp.json()
    except Exception as e:
        return {"error": str(e)}


def convert_to_floats(raw_list):
    """Převede seznam 16bit registrů (raw) na floaty po dvojicích (big-endian)."""
    floats = []
    try:
        for i in range(0, len(raw_list), 2):
            if i + 1 < len(raw_list):
                raw = (raw_list[i] << 16) | raw_list[i + 1]
                val = struct.unpack('>f', struct.pack('>I', raw))[0]
                floats.append(float(round(val, 4)))
        return floats
    except Exception as e:
        print(f"Chyba při převodu na float: {e}")
        return raw_list  # fallback – vrátíme původní hodnoty


def filename_for_date(dt: datetime) -> Path:
    # soubory jsou DD_MM_RR.csv (RR = poslední dvě číslice roku)
    return DATA_DIR / dt.strftime("%d_%m_%y.csv")


def list_available_dates():
    """Dny, pro které existuje CSV (pro Historii/kalendář)."""
    dates = []
    for p in sorted(DATA_DIR.glob("??_??_??.csv")):
        try:
            dt = datetime.strptime(p.stem, "%d_%m_%y")
            dates.append(dt.date())
        except ValueError:
            continue
    return dates


def _safe_float(v, default=0.0):
    try:
        return float(str(v).replace(",", "."))
    except Exception:
        return default


def _safe_int(v, default=0):
    try:
        return int(float(v))
    except Exception:
        return default


def _read_csv_generic_for_today(col_indices, with_flags=True):
    """
    Obecná čtečka pro dnešní CSV.
    col_indices: list 0-based indexů sloupců (např. [1,2,3] → sloupce 2–4)
    with_flags: pokud True, čteme i f16,f17,f18,f20 (indexy 15,16,17,19)
    """
    path = filename_for_date(datetime.now())
    if not path.exists():
        return None

    times = []
    cols = [[] for _ in col_indices]
    f16, f17, f18, f20 = [], [], [], []

    with path.open("r", encoding="utf-8", newline="") as f:
        reader = csv.reader(f)
        for row in reader:
            if not row:
                continue
            # zajisti délku
            if len(row) < 20:
                row = row + [""] * (20 - len(row))

            times.append(row[0].strip())
            for j, ci in enumerate(col_indices):
                cols[j].append(_safe_float(row[ci]))

            if with_flags:
                # POZOR: 16→index15, 17→16, 18→17, 20→19
                f16.append(_safe_int(row[15]))
                f17.append(_safe_int(row[16]))
                f18.append(_safe_int(row[17]))
                f20.append(_safe_int(row[19]))

    out = {
        "times": times,
        "series": cols
    }
    if with_flags:
        out.update({"f16": f16, "f17": f17, "f18": f18, "f20": f20})
    return out


def read_csv_2_4_for_today():
    """Pro první graf (AL1–AL3): sloupce 2–4 (indexy 1,2,3)."""
    d = _read_csv_generic_for_today([1, 2, 3], with_flags=True)
    if not d:
        return None
    a2, a3, a4 = d["series"]
    return {
        "times": d["times"],
        "a2": a2, "a3": a3, "a4": a4,
        "f16": d["f16"], "f17": d["f17"], "f18": d["f18"], "f20": d["f20"]
    }


def read_csv_5_7_for_today():
    """Pro druhý graf (AL4–AL6): sloupce 5–7 (indexy 4,5,6)."""
    d = _read_csv_generic_for_today([4, 5, 6], with_flags=True)
    if not d:
        return None
    a5, a6, a7 = d["series"]
    return {
        "times": d["times"],
        "a5": a5, "a6": a6, "a7": a7,
        "f16": d["f16"], "f17": d["f17"], "f18": d["f18"], "f20": d["f20"]
    }


# ========= TVÉ PŮVODNÍ FUNKCE PRO CRLs (ponechávám, jen lehce zpevněno) =========
def transferit(INs, OUs):
    CRLs = 3
    if INs is True and OUs is True:
        CRLs = 1
    if INs is False and OUs is False:
        CRLs = 2
    return CRLs


def cahnge_INs(INs):
    # pozor na prázdné INs
    if not isinstance(INs, list) or not INs:
        return [False, False, False, False, False]
    vstupy = [INs, INs[0], INs[4] if len(INs) > 4 else False, INs[5] if len(INs) > 5 else False, INs[6] if len(INs) > 6 else False]
    return vstupy


def cahnge_OUs(OUs):
    if not isinstance(OUs, list) or not OUs:
        return [False, False, False, False, False]
    vystupy = [OUs, OUs[0], OUs[1] if len(OUs) > 1 else False, OUs[2] if len(OUs) > 2 else False, OUs[3] if len(OUs) > 3 else False]
    return vystupy


def change_to_CRLs(INs, OUs):
    # bezpečné defaulty
    CRLs = [2] * 16
    if len(INs) > 1 and len(OUs) > 1 and INs[1] is True and OUs[1] is True:
        CRLs = [1] * 16
    if len(INs) > 2 and len(OUs) > 2:
        CRLs[3] = transferit(INs[2], OUs[2])
    if len(INs) > 3 and len(OUs) > 3:
        CRLs[4] = transferit(INs[3], OUs[3])
    if len(INs) > 4 and len(OUs) > 4:
        CRLs[5] = transferit(INs[4], OUs[4])
    if len(INs) > 1 and len(OUs) > 1 and INs[1] is False and OUs[1] is False:
        CRLs = [3] * 16
    if len(INs) > 1 and len(OUs) > 1 and INs[1] is False and OUs[1] is True:
        CRLs = [3] * 16
    return CRLs


def load_curs():
    # Čtení vstupů (instr 7) a výstupů (instr 2) – uprav dle reality
    req = {"ip": "192.168.11.155", "port": 503, "instr": 7, "addr": 1, "count": 8, "type": "raw"}
    data = call_modbus(req)
    inD = ensure_list(data.get("data") if isinstance(data, dict) else [])
    req = {"ip": "192.168.11.155", "port": 503, "instr": 2, "addr": 8193, "count": 8}
    data = call_modbus(req)
    outD = ensure_list(data.get("data") if isinstance(data, dict) else [])
    outD = cahnge_OUs(outD)
    inD = cahnge_INs(inD)
    CRLs = change_to_CRLs(inD, outD)
    M_block = outD[0]
    return (CRLs,M_block)


# ========= DATOVÉ ZDROJE PRO HLAVNÍ STRÁNKU =========
def get_live_headers_and_ul():
    """Načte okamžité AMPs/VOLs/TEEs a CRLs pro overlaye (AL1–6, UL1–6, SVG)."""
    # AMPs 1–6
    req = {"ip": "192.168.11.155", "port": 503, "instr": 1, "addr": 0, "count": 12, "type": "raw"}
    data = call_modbus(req)
    amps = convert_to_floats(ensure_list(data.get("data") if isinstance(data, dict) else []))

    # VOLs 1–6
    req = {"ip": "192.168.11.155", "port": 503, "instr": 1, "addr": 13, "count": 12, "type": "raw"}
    data = call_modbus(req)
    vols = convert_to_floats(ensure_list(data.get("data") if isinstance(data, dict) else []))

    # TEEs 1–2 (pokud je potřebuješ na hlavní stránce do budoucna)
    req = {"ip": "192.168.11.155", "port": 503, "instr": 1, "addr": 25, "count": 4, "type": "raw"}
    data = call_modbus(req)
    tees = convert_to_floats(ensure_list(data.get("data") if isinstance(data, dict) else []))

    # CRLs pro SVG
    crls = load_curs()
    M_block = crls[1]
    crls  = crls[0]
    # Stav M_block a limit M_max – zatím demo/hardcode; můžeš načíst z registru
    M_max = 64

    # AL1–6 overlay hodnoty = poslední známé
    amps_head = []
    for i in range(6):
        amps_head.append(round(amps[i] if i < len(amps) else 0.0, 1))

    return {
        "vols": vols[:6],
        "amps_head": amps_head,   # AL1..AL6
        "tees": tees[:2],
        "crls": crls,
        "M_max": M_max,
        "M_block": M_block,
    }


# ========= ROUTY – HLAVNÍ STRÁNKA =========
@app.route("/")
def dashboard():
    # jen render šablony; data si front-end stáhne z /api/main
    return render_template("index.html")


@app.route("/api/main")
def api_main():
    """
    JSON pro hlavní stránku:
    - časová řada AL1–3 z CSV (sloupce 2–4) + f16..f20
    - časová řada AL4–6 z CSV (sloupce 5–7) + f16..f20
    - AL1–6 (poslední hodnoty) a UL1–6 z Modbusu
    - CRLs (SVG), M_max, M_block
    """
    head = get_live_headers_and_ul()

    csv_24 = read_csv_2_4_for_today()
    csv_57 = read_csv_5_7_for_today()

    # fallbacky prázdných polí, když CSV ještě není
    resp = {
        "times": csv_24["times"] if csv_24 else [],
        "a2": csv_24["a2"] if csv_24 else [],
        "a3": csv_24["a3"] if csv_24 else [],
        "a4": csv_24["a4"] if csv_24 else [],
        "f16": csv_24["f16"] if csv_24 else [],
        "f17": csv_24["f17"] if csv_24 else [],
        "f18": csv_24["f18"] if csv_24 else [],
        "f20": csv_24["f20"] if csv_24 else [],

        "csv_times": csv_57["times"] if csv_57 else [],
        "csv_a5": csv_57["a5"] if csv_57 else [],
        "csv_a6": csv_57["a6"] if csv_57 else [],
        "csv_a7": csv_57["a7"] if csv_57 else [],
        "csv_f16": csv_57["f16"] if csv_57 else [],
        "csv_f17": csv_57["f17"] if csv_57 else [],
        "csv_f18": csv_57["f18"] if csv_57 else [],
        "csv_f20": csv_57["f20"] if csv_57 else [],
    }
    resp.update(head)
    return jsonify(resp)


@app.route("/api/reset", methods=["POST"])
def api_reset():
    """Dálkový RESET přes tvé Modbus API."""
    payload = {
        "ip": "192.168.11.155",
        "port": 503,
        "instr": 6,
        "addr": 8193,
        "count": 1,
        "type": "raw"
    }
    try:
        r = requests.post(
            MODBUS_API_URL,
            json=payload,
            headers={"X-API-Key": API_KEY, "Content-Type": "application/json"},
            timeout=5,
        )
        ok = (200 <= r.status_code < 300)
        return jsonify({"ok": ok, "status": r.status_code, "resp": r.text}), (200 if ok else 502)
    except Exception as e:
        return jsonify({"ok": False, "error": str(e)}), 500


# ========= HISTORIE (ponecháno, ale opraveny indexy a přidán f20) =========
def parse_csv_for_date(dt: datetime):
    """Historie: vrátí times, A2–A4, V7–V9 a flagy f16,f17,f18,f20 pro daný den."""
    path = filename_for_date(dt)
    if not path.exists():
        return None

    times = []
    col2, col3, col4 = [], [], []
    col7, col8, col9 = [], [], []
    flag16, flag17, flag18, flag20 = [], [], [], []

    with path.open("r", encoding="utf-8", newline="") as f:
        reader = csv.reader(f)
        for row in reader:
            if not row:
                continue
            if len(row) < 20:
                row = row + [""] * (20 - len(row))

            times.append(row[0].strip())

            col2.append(_safe_float(row[1]))
            col3.append(_safe_float(row[2]))
            col4.append(_safe_float(row[3]))
            col7.append(_safe_float(row[6]))
            col8.append(_safe_float(row[7]))
            col9.append(_safe_float(row[8]))

            # 16→15, 17→16, 18→17, 20→19
            flag16.append(_safe_int(row[15]))
            flag17.append(_safe_int(row[16]))
            flag18.append(_safe_int(row[17]))
            flag20.append(_safe_int(row[19]))

    return {
        "date": dt.strftime("%Y-%m-%d"),
        "times": times,
        "a2": col2, "a3": col3, "a4": col4,
        "v7": col7, "v8": col8, "v9": col9,
        "f16": flag16, "f17": flag17, "f18": flag18, "f20": flag20
    }


@app.route("/historie")
def historie():
    return render_template("historie.html")


@app.route("/api/history/available")
def api_history_available():
    dates = list_available_dates()
    return jsonify({"dates": [d.isoformat() for d in dates]})


@app.route("/api/history/latest")
def api_history_latest():
    dates = list_available_dates()
    if not dates:
        return jsonify({"dates": [], "data": None})
    last = dates[-1]
    data = parse_csv_for_date(datetime.combine(last, datetime.min.time()))
    return jsonify({"dates": [d.isoformat() for d in dates], "data": data})


@app.route("/api/history/data")
def api_history_data():
    ds = request.args.get("date", "")
    try:
        dt = datetime.strptime(ds, "%Y-%m-%d")
    except ValueError:
        abort(400, "Bad date")
    data = parse_csv_for_date(dt)
    if not data:
        abort(404, "No CSV for date")
    return jsonify(data)


# prázdné stránky pro šipky v historii
@app.route("/historie-prev")
def historie_prev():
    return render_template("placeholder.html", title="Předchozí")


@app.route("/historie-next")
def historie_next():
    return render_template("placeholder.html", title="Další")


# ========= START =========
if __name__ == "__main__":
    # běž na stejné adrese jako dřív (můžeš změnit podle svého)
    app.run(host="0.0.0.0", port=5000, debug=True)