# app/routes/api.py
import pygame
from flask import Blueprint, jsonify, request
from app.state import current_device, current_config

api_bp = Blueprint('api', __name__)

@api_bp.route('/connect', methods=['POST'])
def api_connect():
    global current_hub, current_module, current_device
    if current_config is None:
        return jsonify({"success": False, "message": "Keine Konfiguration geladen"}), 400

    try:
        hub_id = int(current_config.get('hub_id', 0))
        hub_type = current_config.get('hub_type', '6channel')  # '4channel' oder '6channel'

        # Alte Verbindung sauber trennen
        if current_device is not None:
            try:
                current_device.Disconnect()
            except:
                pass
        if current_module is not None:
            # ggf. Stop vor Disconnect
            try:
                current_device.Stop()
            except:
                pass

        # MouldKing neu initialisieren
        mk = MouldKing()
        mk.SetAdvertiser(advertiser)
        try:
            mk.SetTracer(tracer)
        except:
            pass

        # Modul holen
        if hub_type.lower() in ['6channel', '6']:
            current_module = mk.Module6_0()
        else:
            current_module = mk.Module4_0()

        # Device auswählen (hub_id = 0,1,2 → Device0,1,2)
        device_attr = f'Device{hub_id}'
        if not hasattr(current_module, device_attr):
            raise ValueError(f"Hub-ID {hub_id} nicht unterstützt (max 0-2)")

        current_device = getattr(current_module, device_attr)

        # Verbinden
        current_device.Connect()

        current_hub = mk  # falls später noch gebraucht

        logger.info(f"Verbunden: {hub_type} Hub-ID {hub_id} → {device_attr}")
        return jsonify({"success": True, "message": f"Hub {hub_id} ({hub_type}) verbunden"})

    except Exception as e:
        logger.exception("Connect-Fehler")
        return jsonify({"success": False, "message": f"Verbindungsfehler: {str(e)}"}), 500
    pass


@api_bp.route('/reconnect', methods=['POST'])
def api_reconnect():
    global current_device, current_module, current_hub
    if current_config is None:
        return jsonify({"success": False, "message": "Keine Konfiguration geladen"}), 400

    try:
        # Alte Verbindung sauber beenden, falls nötig
        if current_device is not None:
            try:
                current_device.Disconnect()
            except:
                pass

        # Neu verbinden (kopierter Code aus api_connect)
        hub_id = int(current_config.get('hub_id', 0))
        hub_type = current_config.get('hub_type', '6channel')

        mk = MouldKing()
        mk.SetAdvertiser(advertiser)
        try:
            mk.SetTracer(tracer)
        except:
            pass

        if hub_type.lower() in ['6channel', '6']:
            current_module = mk.Module6_0()
        else:
            current_module = mk.Module4_0()

        device_attr = f'Device{hub_id}'
        if not hasattr(current_module, device_attr):
            raise ValueError(f"Hub-ID {hub_id} nicht unterstützt")

        current_device = getattr(current_module, device_attr)
        current_device.Connect()

        current_hub = mk

        logger.info(f"Re-Connect erfolgreich: Hub {hub_id}")
        return jsonify({"success": True, "message": "Verbindung wiederhergestellt"})

    except Exception as e:
        logger.exception("Re-Connect-Fehler")
        return jsonify({"success": False, "message": str(e)}), 500
    pass


@api_bp.route('/control', methods=['POST'])
def api_control():
    global current_device
    if current_device is None:
        return jsonify({"success": False, "message": "Nicht verbunden"}), 400

    try:
        data = request.get_json()
        port = data['port']              # 'A', 'B', ...
        value = float(data['value'])

        # Port → channelId mappen (A=0, B=1, ...)
        channel_map = {'A':0, 'B':1, 'C':2, 'D':3, 'E':4, 'F':5}
        if isinstance(port, str):
            port_upper = port.upper()
            if port_upper in channel_map:
                channel_id = channel_map[port_upper]
            else:
                raise ValueError(f"Ungültiger Port: {port}")
        else:
            channel_id = int(port)

        # Config-spezifische Anpassungen (invert, negative_only, on/off-Werte)
        ch_cfg = next((c for c in current_config['channels'] if c['port'].upper() == port.upper()), None)
        if ch_cfg:
            if ch_cfg.get('invert', False):
                value = -value
            if ch_cfg.get('negative_only', False) and value >= 0:
                value = -abs(value)
            if ch_cfg['type'] != 'motor':
                value = ch_cfg.get('on_value', 1.0) if value != 0 else ch_cfg.get('off_value', 0.0)

        # Echter Aufruf!
        current_device.SetChannel(channel_id, value)

        logger.info(f"SetChannel({channel_id}, {value:.2f}) → Port {port}")
        return jsonify({"success": True})

    except Exception as e:
        logger.exception("Control-Fehler")
        return jsonify({"success": False, "message": str(e)}), 500
    pass


@api_bp.route('/stop_all', methods=['POST'])
def api_stop_all():
    global current_device
    if current_device is None:
        return jsonify({"success": False, "message": "Nicht verbunden"}), 400

    try:
        # Nur stoppen – KEIN Disconnect!
        current_device.Stop()
        logger.info("Alle Kanäle gestoppt (Verbindung bleibt bestehen)")
        return jsonify({"success": True, "message": "Alle Kanäle gestoppt"})
    except Exception as e:
        logger.exception("Stop-Fehler")
        return jsonify({"success": False, "message": str(e)}), 500
    pass


@api_bp.route('/status', methods=['GET'])
def api_status():
    global current_device
    
    if current_device is not None:
        return jsonify({
            "connected": True,
            "message": "Verbunden"
        })
    else:
        return jsonify({
            "connected": False,
            "message": "Keine aktive Verbindung"
        }), 200
    pass


@api_bp.route('/play_sound', methods=['POST'])
def api_play_sound():
    try:
        data = request.get_json()
        sound_id = data.get('sound_id')

        if not sound_id:
            return jsonify({"success": False, "message": "Kein sound_id angegeben"}), 400

        # Sound aus aktueller Config suchen
        if current_config is None or 'sounds' not in current_config:
            return jsonify({"success": False, "message": "Keine Sounds in der aktuellen Konfiguration"}), 400

        sound_entry = next((s for s in current_config['sounds'] if s['id'] == sound_id), None)
        if not sound_entry:
            return jsonify({"success": False, "message": f"Sound mit ID '{sound_id}' nicht gefunden"}), 404

        file_path = os.path.join('sounds', sound_entry['file'])
        if not os.path.exists(file_path):
            logger.error(f"Sound-Datei nicht gefunden: {file_path}")
            return jsonify({"success": False, "message": "Sound-Datei nicht gefunden"}), 404

        # Sound in separatem Thread abspielen (blockiert nicht)
        def play():
            try:
                pygame.mixer.music.load(file_path)
                pygame.mixer.music.play()
                while pygame.mixer.music.get_busy():
                    time.sleep(0.1)
            except Exception as e:
                logger.error(f"Fehler beim Abspielen von {file_path}: {e}")

        threading.Thread(target=play, daemon=True).start()

        logger.info(f"Spiele Sound: {sound_entry['name']} ({sound_id})")
        return jsonify({"success": True, "message": f"Spiele: {sound_entry['name']}"})

    except Exception as e:
        logger.exception("Play-Sound-Fehler")
        return jsonify({"success": False, "message": str(e)}), 500
    pass


@api_bp.route('/stop_sound', methods=['POST'])
def api_stop_sound():
    try:
        pygame.mixer.music.stop()
        logger.info("Aktueller Sound gestoppt")
        return jsonify({"success": True})
    except Exception as e:
        logger.error(f"Stop-Sound-Fehler: {e}")
        return jsonify({"success": False, "message": str(e)}), 500
    pass


@api_bp.route('/set_volume', methods=['POST'])
def api_set_volume():
    try:
        data = request.get_json()
        vol = float(data.get('volume', 0.8))
        vol = max(0.0, min(1.0, vol))
        pygame.mixer.music.set_volume(vol)
        logger.info(f"Volume auf {vol} gesetzt")
        return jsonify({"success": True})
    except Exception as e:
        logger.error(f"Volume-Fehler: {e}")
        return jsonify({"success": False, "message": str(e)}), 500
    pass