#!/usr/bin/env python3
"""
Synchronizuje friendly_names w ibsystem2mqtt.yaml z dokumentacji projektu.
Źródło: /smart-home/proj-ib-lighting-rs485-zarki.yaml
"""
import yaml, re, sys, os, subprocess, shutil
from datetime import datetime

PROJECT_YAML  = "/smart-home/proj-ib-lighting-rs485-zarki.yaml"
CONFIG_YAML   = "/ibsystem/ibsystem2mqtt.yaml"
MQTT_HOST     = "192.168.50.151"
MQTT_USER     = "mqtt"
MQTT_PASS     = "mqtt123"

def device_id_to_rs_id(device_id):
    """'rs.0.id.35' → ('0', '35')"""
    m = re.match(r"rs\.(\d+)\.id\.(\d+)", device_id)
    return (m.group(1), m.group(2)) if m else (None, None)

def io_key(rs, dev_id, io_id):
    """'output.do.0' → 'rs0_id35_output_do_0'"""
    safe = re.sub(r"[^a-zA-Z0-9]+", "_", io_id).strip("_")
    return f"rs{rs}_id{dev_id}_{safe}"

def parse_project_yaml(path):
    with open(path) as f:
        data = yaml.safe_load(f)
    
    devices = data["project"]["hardware_specification"]["devices"]
    names = {}
    
    for dev in devices:
        device_id = dev.get("device_id", "")
        location  = dev.get("location", "").strip()
        rs, dev_id = device_id_to_rs_id(device_id)
        if not rs:
            continue
        
        # Nazwa urządzenia = lokalizacja + ID
        if location:
            names[f"rs{rs}_id{dev_id}"] = f"{location} - ID{dev_id}"
        
        # Nazwy wyjść DO (sterowalne)
        for io in dev.get("io", []):
            io_id   = io.get("io_id", "")
            desc    = io.get("description", "").strip()
            status  = io.get("status", "ok")
            
            # Tylko output.do.* z niepustym opisem i status != nc
            if io_id.startswith("output.do.") and desc and status != "nc":
                # Pomiń generyczne opisy
                if not desc.startswith("Opcjonalne"):
                    names[io_key(rs, dev_id, io_id)] = desc
    
    return names

def update_config(config_path, new_names, dry_run=False):
    with open(config_path) as f:
        config = yaml.safe_load(f)
    
    old_names = config.get("friendly_names") or {}
    
    # Oblicz diff
    changed = {}
    all_keys = set(old_names) | set(new_names)
    for k in sorted(all_keys):
        o, n = old_names.get(k), new_names.get(k)
        if o != n:
            changed[k] = (o, n)
    
    if not changed:
        print(f"[{datetime.now():%H:%M:%S}] Brak zmian.")
        return False
    
    print(f"[{datetime.now():%H:%M:%S}] Zmiany ({len(changed)}):")
    for k, (o, n) in changed.items():
        print(f"  {k}: {o!r} → {n!r}")
    
    if dry_run:
        print("  (dry-run, nie zapisuję)")
        return True
    
    # Zapisz backup
    shutil.copy(config_path, config_path + ".bak")
    config["friendly_names"] = new_names
    with open(config_path, "w") as f:
        yaml.dump(config, f, allow_unicode=True, default_flow_style=False, sort_keys=False)
    print(f"  Zapisano {config_path}")
    return True

def reload_ibsystem():
    """Wyczyść retained MQTT discovery i zrestartuj serwis."""
    print("Czyszczę MQTT discovery cache...")
    os.system(
        f"timeout 5 mosquitto_sub -h {MQTT_HOST} -u {MQTT_USER} -P {MQTT_PASS} "
        f"-t 'homeassistant/#' --retained-only -v 2>/dev/null | "
        f"grep '/config' | grep 'ibsystem' | awk '{{print $1}}' | "
        f"while read t; do mosquitto_pub -h {MQTT_HOST} -u {MQTT_USER} -P {MQTT_PASS} "
        f"-t \"$t\" -n -r; done"
    )
    print("Restartuję ibsystem2mqtt...")
    subprocess.run(["systemctl", "restart", "ibsystem2mqtt"], check=True)
    print("Gotowe.")

def main():
    dry_run = "--dry-run" in sys.argv
    print(f"[{datetime.now():%H:%M:%S}] Parsing {PROJECT_YAML}...")
    
    try:
        names = parse_project_yaml(PROJECT_YAML)
    except Exception as e:
        print(f"BŁĄD parsowania YAML: {e}")
        sys.exit(1)
    
    print(f"  Znaleziono {len(names)} wpisów.")
    
    changed = update_config(CONFIG_YAML, names, dry_run)
    
    if changed and not dry_run:
        reload_ibsystem()

if __name__ == "__main__":
    main()
