import subprocess
import threading
import time
import pymysql
import logging
import configparser
import psutil

CONFIG_PATH = "/app/config.ini"
config = configparser.ConfigParser()
config.read(CONFIG_PATH)
loglevel_str = config["log"]["level"].upper()
loglevel = getattr(logging, loglevel_str, logging.INFO)
logging.basicConfig(level=loglevel)

DB_CONFIG = {
    'host': config["database"]["host"],
    'user': config["database"]["user"],
    'password': config["database"]["password"],
    'database': config["database"]["database"]
}

running_services = {}

def get_process_on_port(port):
    for conn in psutil.net_connections(kind='inet'):
        if conn.laddr.port == port and conn.status == psutil.CONN_LISTEN:
            pid = conn.pid
            if pid is None:
                continue
            try:
                proc = psutil.Process(pid)
                return {
                    'pid': pid,
                    'name': proc.name(),
                    'cmdline': proc.cmdline()
                }
            except (psutil.NoSuchProcess, psutil.AccessDenied):
                continue
    return None

def initialize_running_services_from_db(db_config):
    try:
        conn = pymysql.connect(**db_config)
        cursor = conn.cursor(pymysql.cursors.DictCursor)
        cursor.execute("SELECT name, tcpport FROM receivers;")
        rows = cursor.fetchall()
        for row in rows:
            name = row['name']
            port = row['tcpport']
            proc_info = get_process_on_port(port)
            if proc_info:
                logging.info(f"[INIT] Found existing service '{name}' on port {port}, PID={proc_info['pid']}, Cmd={proc_info['cmdline']}")
                running_services[name] = {
                    "pid": proc_info["pid"],
                    "cmdline": proc_info["cmdline"]
                }
        cursor.close()
        conn.close()
    except Exception as e:
        logging.exception("[INIT] Failed to detect existing services")

def watchdog(db_config):
    global running_services
    while True:
        try:
            thread_conn = pymysql.connect(**db_config)
            cursor = thread_conn.cursor(pymysql.cursors.DictCursor)
            cursor.execute("SELECT name, type, tcpport, enabled FROM receivers;")
            rows = cursor.fetchall()
            cursor.close()
            thread_conn.close()
            for row in rows:
                name = row["name"]
                receiver_type = row["type"]
                port = row["tcpport"]
                enabled = row["enabled"]

                if receiver_type != "SIA-DC09":
                    continue

                if enabled == 1 and name not in running_services:
                    binary_path = "/app/tcp_sia_server.bin"
                    logging.info(f"[WATCHDOG] Starting receiver '{name}' on port {port}")
                    start_service(name, binary_path, port)

                elif enabled == 0:
                    proc_info = running_services.get(name)
                    if proc_info and isinstance(proc_info, subprocess.Popen):
                        logging.info(f"[WATCHDOG] Stopping disabled receiver '{name}' (started by script)")
                        proc_info.terminate()
                        proc_info.wait()
                        del running_services[name]
                    else:
                        # Kill external process using psutil
                        port = row["tcpport"]
                        try:
                            for conn in psutil.net_connections(kind='inet'):
                                if conn.laddr.port == port and conn.status == psutil.CONN_LISTEN:
                                    pid = conn.pid
                                    if pid:
                                        logging.warning(
                                            f"[WATCHDOG] Force killing external process on port {port} (PID {pid}) for receiver '{name}'")
                                        psutil.Process(pid).kill()
                                        if name in running_services:
                                            del running_services[name]
                        except Exception as e:
                            logging.exception(f"[WATCHDOG] Failed to kill external process for receiver '{name}'")

            log_thread_status()
            time.sleep(3)
        except Exception as e:
            logging.exception(f"[WATCHDOG] Error during check: {e}")

def start_service(name, binary_path, port=None):
    def run():
        cmd = [binary_path]
        if port:
            cmd.append(str(port))
        logging.info(f"[WATCHDOG] Starting {name} on port {port}...")
        process = subprocess.Popen(cmd)
        running_services[name] = {
            "popen": process
        }
        process.wait()
        logging.warning(f"[WATCHDOG] {name} exited.")
    thread = threading.Thread(target=run, daemon=True)
    thread.start()

def log_thread_status():
    running = list(running_services.keys())
    logging.debug(f"[STATUS] Running services: {running if running else 'None'}")

if __name__ == "__main__":
    initialize_running_services_from_db(DB_CONFIG)
    logging.debug(f"[INIT] Active running_services: {list(running_services.keys())}")
    watchdog(DB_CONFIG)
