import argparse
import json
import logging
import os
import random
import sys
import time

import paho.mqtt.client as mqtt


DEFAULT_BROKER = "141.75.223.13"
DEFAULT_PORT = 1883
DEFAULT_TOPIC = "PREDICTION"
DEFAULT_QOS = 0
DEFAULT_INTERVAL_SECONDS = 5.0
DEFAULT_START_ID = 1
DEFAULT_CLIENT_ID = "mqtt-simulator"
DEFAULT_LOG_FILE = "logs/mqtt_simulator.log"


def env_int(name, default):
    value = os.getenv(name)
    if value is None or value.strip() == "":
        return default

    try:
        return int(value)
    except ValueError:
        return default


def env_float(name, default):
    value = os.getenv(name)
    if value is None or value.strip() == "":
        return default

    try:
        return float(value)
    except ValueError:
        return default


def build_args():
    parser = argparse.ArgumentParser(
        description="MQTT simulator for binary prediction events."
    )

    parser.add_argument("--broker", default=os.getenv("MQTT_SIM_BROKER", DEFAULT_BROKER))
    parser.add_argument("--port", type=int, default=env_int("MQTT_SIM_PORT", DEFAULT_PORT))
    parser.add_argument("--topic", default=os.getenv("MQTT_SIM_TOPIC", DEFAULT_TOPIC))
    parser.add_argument("--username", default=os.getenv("MQTT_SIM_USERNAME"))
    parser.add_argument("--password", default=os.getenv("MQTT_SIM_PASSWORD"))
    parser.add_argument("--qos", type=int, choices=[0, 1, 2], default=env_int("MQTT_SIM_QOS", DEFAULT_QOS))
    parser.add_argument(
        "--interval-seconds",
        type=float,
        default=env_float("MQTT_SIM_INTERVAL_SECONDS", DEFAULT_INTERVAL_SECONDS),
    )
    parser.add_argument("--start-id", type=int, default=env_int("MQTT_SIM_START_ID", DEFAULT_START_ID))
    parser.add_argument("--client-id", default=os.getenv("MQTT_SIM_CLIENT_ID", DEFAULT_CLIENT_ID))
    parser.add_argument("--log-file", default=os.getenv("MQTT_SIM_LOG_FILE", DEFAULT_LOG_FILE))

    return parser.parse_args()


def configure_logging(log_file):
    log_dir = os.path.dirname(log_file)
    if log_dir:
        os.makedirs(log_dir, exist_ok=True)

    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s - %(levelname)s - %(message)s",
        handlers=[
            logging.FileHandler(log_file),
            logging.StreamHandler(sys.stdout),
        ],
        force=True,
    )


def on_connect(client, userdata, flags, rc):
    if rc == 0:
        logging.info("Erfolgreich mit Broker verbunden")
    else:
        logging.error("Verbindung fehlgeschlagen mit Code %s", rc)


def main():
    args = build_args()
    configure_logging(args.log_file)

    logging.info("Python script gestartet")
    logging.info(
        "Konfiguration: broker=%s port=%s topic=%s qos=%s interval=%s",
        args.broker,
        args.port,
        args.topic,
        args.qos,
        args.interval_seconds,
    )

    client = mqtt.Client(client_id=args.client_id)

    if args.username:
        client.username_pw_set(args.username, args.password)

    client.on_connect = on_connect

    try:
        logging.info("Verbinde mit Broker %s:%s", args.broker, args.port)
        client.connect(args.broker, args.port, 60)
        client.loop_start()

        logging.info("Starte kontinuierliches Senden...")

        current_id = args.start_id

        while True:
            payload = {
                "valid": True,
                "_id": current_id,
                "prediction": random.randint(0, 1),
            }

            json_payload = json.dumps(payload)
            client.publish(args.topic, json_payload, qos=args.qos)
            logging.info("Gesendet an '%s': %s", args.topic, json_payload)

            current_id += 1
            time.sleep(args.interval_seconds)

    except KeyboardInterrupt:
        logging.info("Publisher manuell beendet")
        sys.exit(0)

    except Exception:
        logging.exception("Unerwarteter Fehler")
        sys.exit(1)

    finally:
        try:
            client.loop_stop()
            client.disconnect()
        except Exception:
            pass


if __name__ == "__main__":
    main()
