"""
PC Monitor - Serveur Flask pour monitoring hardware
Supporte plusieurs plugins: LibreHardwareMonitor, HWiNFO, Plexamp, etc.
"""
from flask import Flask, render_template, jsonify, request
import json
import os
import subprocess
from threading import Thread
import time

# Import du système de plugins
from plugins import get_plugin, get_available_plugins, PLUGINS
from plugins import get_media_plugin, get_available_media_plugins, MEDIA_PLUGINS

app = Flask(__name__)
app.config['SECRET_KEY'] = 'votre-cle-secrete-ici'

# Fichiers de configuration
CONFIG_FILE = 'config.json'

# Plugins actifs (initialisés au démarrage)
active_plugin = None
plexamp_plugin = None

# Configuration par défaut
DEFAULT_CONFIG = {
    "active_plugin": "librehardwaremonitor",
    "theme": "dark",
    "apps": [],
    "apps_tab": "",
    "plugins": {
        "librehardwaremonitor": {
            "host": "127.0.0.1",
            "port": 8085
        },
        "hwinfo": {
            "host": "127.0.0.1",
            "port": 60000
        }
    },
    "media": {
        "plexamp": {
            "enabled": False,
            "host": "127.0.0.1",
            "port": 32400,
            "token": ""
        }
    }
}

DEFAULT_PLUGIN_CONFIG = {
    "tabs": [
        {
            "id": "tab1",
            "name": "Général",
            "sensors": []
        }
    ]
}


# ==================== Gestion de la configuration ====================

def load_config():
    """Charge la configuration globale"""
    if os.path.exists(CONFIG_FILE):
        try:
            with open(CONFIG_FILE, 'r', encoding='utf-8') as f:
                config = json.load(f)
                # Fusionner avec les valeurs par dÃ©faut
                for key, value in DEFAULT_CONFIG.items():
                    if key not in config:
                        config[key] = value
                return config
        except Exception as e:
            print(f"Erreur chargement config: {e}")
            return DEFAULT_CONFIG.copy()
    return DEFAULT_CONFIG.copy()


def save_config(config):
    """Sauvegarde la configuration globale"""
    with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
        json.dump(config, f, indent=2, ensure_ascii=False)


def get_plugin_config_file(plugin_id):
    """Retourne le nom du fichier de config pour un plugin"""
    return f'config_{plugin_id}.json'


def load_plugin_config(plugin_id):
    """Charge la configuration spÃ©cifique Ã  un plugin"""
    config_file = get_plugin_config_file(plugin_id)
    if os.path.exists(config_file):
        try:
            with open(config_file, 'r', encoding='utf-8') as f:
                return json.load(f)
        except Exception as e:
            print(f"Erreur chargement config plugin {plugin_id}: {e}")
            return DEFAULT_PLUGIN_CONFIG.copy()
    return DEFAULT_PLUGIN_CONFIG.copy()


def save_plugin_config(plugin_id, config):
    """Sauvegarde la configuration spÃ©cifique Ã  un plugin"""
    config_file = get_plugin_config_file(plugin_id)
    with open(config_file, 'w', encoding='utf-8') as f:
        json.dump(config, f, indent=2, ensure_ascii=False)


def get_merged_config():
    """
    Retourne une config fusionnÃ©e (global + plugin actif)
    Pour compatibilitÃ© avec le code existant
    """
    global_config = load_config()
    plugin_id = global_config.get('active_plugin', 'librehardwaremonitor')
    plugin_config = load_plugin_config(plugin_id)
    
    # Fusionner
    merged = global_config.copy()
    merged['tabs'] = plugin_config.get('tabs', [])
    
    return merged


def save_merged_config(config):
    """
    Sauvegarde une config fusionnÃ©e
    SÃ©pare les donnÃ©es globales et plugin
    """
    global_config = load_config()
    plugin_id = global_config.get('active_plugin', 'librehardwaremonitor')
    
    # Extraire les donnÃ©es plugin
    plugin_config = {
        'tabs': config.get('tabs', [])
    }
    
    # Mettre Ã  jour la config globale
    global_config['theme'] = config.get('theme', 'dark')
    global_config['apps'] = config.get('apps', [])
    global_config['apps_tab'] = config.get('apps_tab', '')
    
    # Sauvegarder les deux
    save_config(global_config)
    save_plugin_config(plugin_id, plugin_config)


# ==================== Gestion du plugin actif ====================

def init_plugin():
    """Initialise le plugin actif"""
    global active_plugin
    
    config = load_config()
    plugin_id = config.get('active_plugin', 'librehardwaremonitor')
    plugin_config = config.get('plugins', {}).get(plugin_id, {})
    
    try:
        active_plugin = get_plugin(plugin_id, plugin_config)
        print(f"Plugin initialisÃ©: {active_plugin.get_name()}")
    except Exception as e:
        print(f"Erreur initialisation plugin {plugin_id}: {e}")
        # Fallback sur LHM
        active_plugin = get_plugin('librehardwaremonitor', {'host': '127.0.0.1', 'port': 8085})


def switch_plugin(plugin_id):
    """Change le plugin actif"""
    global active_plugin
    
    config = load_config()
    plugin_config = config.get('plugins', {}).get(plugin_id, {})
    
    try:
        active_plugin = get_plugin(plugin_id, plugin_config)
        config['active_plugin'] = plugin_id
        save_config(config)
        print(f"Plugin changÃ©: {active_plugin.get_name()}")
        return True
    except Exception as e:
        print(f"Erreur changement plugin: {e}")
        return False


# ==================== Thread d'historique ====================

def update_history_loop():
    """Boucle pour mettre Ã  jour l'historique des capteurs"""
    global active_plugin
    
    while True:
        if active_plugin:
            try:
                data = active_plugin.get_data()
                if data:
                    sensors = active_plugin.parse_sensors(data)
                    active_plugin.update_history(sensors)
            except Exception as e:
                print(f"Erreur update history: {e}")
        time.sleep(1)


# ==================== Routes Pages ====================

@app.route('/')
def index():
    """Page d'accueil - redirige vers dashboard"""
    return render_template('dashboard.html')


@app.route('/admin')
def admin():
    """Page d'administration"""
    return render_template('admin.html')


@app.route('/dashboard')
def dashboard():
    """Page de dashboard"""
    return render_template('dashboard.html')


# ==================== API Plugins ====================

@app.route('/api/plugins')
def api_plugins_list():
    """Liste des plugins disponibles"""
    plugins = get_available_plugins()
    config = load_config()
    active_id = config.get('active_plugin', 'librehardwaremonitor')
    
    # Ajouter l'Ã©tat actif
    for plugin in plugins:
        plugin['active'] = plugin['id'] == active_id
        plugin['config'] = config.get('plugins', {}).get(plugin['id'], {})
    
    return jsonify(plugins)


@app.route('/api/plugins/active')
def api_plugins_active():
    """Retourne le plugin actif"""
    global active_plugin
    
    if not active_plugin:
        return jsonify({'error': 'Aucun plugin actif'}), 500
    
    config = load_config()
    plugin_id = active_plugin.get_id()
    
    return jsonify({
        'id': plugin_id,
        'name': active_plugin.get_name(),
        'config': config.get('plugins', {}).get(plugin_id, {})
    })


@app.route('/api/plugins/switch', methods=['POST'])
def api_plugins_switch():
    """Change le plugin actif"""
    data = request.get_json()
    plugin_id = data.get('plugin_id')
    
    if not plugin_id or plugin_id not in PLUGINS:
        return jsonify({'success': False, 'error': 'Plugin invalide'}), 400
    
    if switch_plugin(plugin_id):
        return jsonify({'success': True, 'message': f'Plugin changÃ©: {plugin_id}'})
    else:
        return jsonify({'success': False, 'error': 'Erreur changement plugin'}), 500


@app.route('/api/plugins/config', methods=['POST'])
def api_plugins_config():
    """Met Ã  jour la configuration d'un plugin"""
    data = request.get_json()
    plugin_id = data.get('plugin_id')
    plugin_config = data.get('config', {})
    
    if not plugin_id:
        return jsonify({'success': False, 'error': 'Plugin ID requis'}), 400
    
    config = load_config()
    
    if 'plugins' not in config:
        config['plugins'] = {}
    
    config['plugins'][plugin_id] = plugin_config
    save_config(config)
    
    # Si c'est le plugin actif, le rÃ©initialiser
    if active_plugin and active_plugin.get_id() == plugin_id:
        init_plugin()
    
    return jsonify({'success': True, 'message': 'Configuration mise Ã  jour'})


@app.route('/api/plugins/test', methods=['POST'])
def api_plugins_test():
    """Teste la connexion d'un plugin"""
    data = request.get_json()
    plugin_id = data.get('plugin_id')
    plugin_config = data.get('config', {})
    
    if not plugin_id or plugin_id not in PLUGINS:
        return jsonify({'success': False, 'error': 'Plugin invalide'}), 400
    
    try:
        # CrÃ©er une instance temporaire pour tester
        test_plugin = get_plugin(plugin_id, plugin_config)
        result = test_plugin.test_connection()
        return jsonify(result)
    except Exception as e:
        return jsonify({'success': False, 'error': str(e)}), 500


# ==================== API Capteurs (compatible) ====================

@app.route('/api/lhm/sensors')
def api_lhm_sensors():
    """Retourne la liste complÃ¨te de tous les capteurs"""
    global active_plugin
    
    if not active_plugin:
        return jsonify({"error": "Aucun plugin actif"}), 500
    
    data = active_plugin.get_data()
    if not data:
        return jsonify({"error": "Impossible de rÃ©cupÃ©rer les donnÃ©es"}), 500
    
    sensors = active_plugin.parse_sensors(data)
    
    # Grouper par catÃ©gorie
    grouped = {}
    for sensor in sensors:
        category = sensor.get('category', 'Autre')
        if category not in grouped:
            grouped[category] = []
        grouped[category].append(sensor)
    
    return jsonify(grouped)


@app.route('/api/lhm/hierarchy')
def api_lhm_hierarchy():
    """Retourne la structure hiÃ©rarchique complÃ¨te des capteurs"""
    global active_plugin
    
    if not active_plugin:
        return jsonify({"error": "Aucun plugin actif"}), 500
    
    hierarchy = active_plugin.get_hierarchy()
    if not hierarchy:
        return jsonify({"error": "Impossible de rÃ©cupÃ©rer les donnÃ©es"}), 500
    
    return jsonify(hierarchy)


@app.route('/api/lhm/data')
def api_lhm_data():
    """Retourne les donnÃ©es actuelles des capteurs sÃ©lectionnÃ©s"""
    global active_plugin
    
    if not active_plugin:
        return jsonify({"error": "Aucun plugin actif"}), 500
    
    config = get_merged_config()
    data = active_plugin.get_data()
    
    if not data:
        return jsonify({"error": "Impossible de rÃ©cupÃ©rer les donnÃ©es"}), 500
    
    all_sensors = active_plugin.parse_sensors(data)
    
    # CrÃ©er un dictionnaire pour lookup rapide
    sensor_dict = {s['id']: s for s in all_sensors}
    
    # Organiser par onglets
    result = {
        "tabs": [],
        "timestamp": time.time()
    }
    
    for tab in config.get('tabs', []):
        tab_data = {
            "id": tab['id'],
            "name": tab['name'],
            "sensors": []
        }
        
        for sensor_config in tab.get('sensors', []):
            sensor_id = sensor_config['id']
            if sensor_id in sensor_dict:
                sensor = sensor_dict[sensor_id].copy()
                sensor['show_graph'] = sensor_config.get('show_graph', False)
                sensor['viz_type'] = sensor_config.get('viz_type', 'line')
                sensor['card_size'] = sensor_config.get('card_size', 'medium')
                sensor['font_family'] = sensor_config.get('font_family', 'system')
                sensor['font_bold'] = sensor_config.get('font_bold', True)
                sensor['font_size'] = sensor_config.get('font_size', 'small')
                sensor['hide_value_mobile'] = sensor_config.get('hide_value_mobile', False)
                sensor['show_type_badge'] = sensor_config.get('show_type_badge', True)
                sensor['gauge_options'] = sensor_config.get('gauge_options', {})
                sensor['chart_options'] = sensor_config.get('chart_options', {})
                tab_data['sensors'].append(sensor)
        
        result['tabs'].append(tab_data)
    
    return jsonify(result)


@app.route('/api/lhm/history/<path:sensor_id>')
def api_lhm_history(sensor_id):
    """Retourne l'historique d'un capteur pour le graphique"""
    global active_plugin
    
    if not active_plugin:
        return jsonify({"error": "Aucun plugin actif"}), 500
    
    # Reconstruire l'ID complet
    if not sensor_id.startswith('/'):
        sensor_id = '/' + sensor_id
    
    count = request.args.get('count', 60, type=int)
    history = active_plugin.get_history(sensor_id, count)
    
    return jsonify({
        "sensor_id": sensor_id,
        "values": history,
        "count": len(history)
    })


# ==================== API Configuration ====================

@app.route('/api/config')
def api_config_get():
    """RÃ©cupÃ¨re la configuration actuelle (fusionnÃ©e)"""
    config = get_merged_config()
    return jsonify(config)


@app.route('/api/config', methods=['POST'])
def api_config_save():
    """Sauvegarde la configuration"""
    try:
        config = request.get_json()
        save_merged_config(config)
        return jsonify({"success": True, "message": "Configuration sauvegardÃ©e"})
    except Exception as e:
        return jsonify({"success": False, "error": str(e)}), 500


# ==================== API Applications ====================

@app.route('/api/apps')
def api_apps_list():
    """Liste des applications configurées"""
    config = load_config()
    return jsonify(config.get('apps', []))


@app.route('/api/apps/launch/<int:app_id>', methods=['POST'])
def api_apps_launch(app_id):
    """Lance une application"""
    config = load_config()
    apps = config.get('apps', [])
    
    if app_id < 0 or app_id >= len(apps):
        return jsonify({"success": False, "error": "Application non trouvée"}), 404
    
    app_config = apps[app_id]
    
    try:
        subprocess.Popen(app_config['path'], shell=True)
        return jsonify({"success": True, "message": f"{app_config['name']} lancée"})
    except Exception as e:
        return jsonify({"success": False, "error": str(e)}), 500


# ==================== API Plexamp ====================

def init_plexamp():
    """Initialise le plugin Plexamp si configuré"""
    global plexamp_plugin
    
    config = load_config()
    plexamp_config = config.get('media', {}).get('plexamp', {})
    
    if plexamp_config.get('enabled') and plexamp_config.get('token'):
        try:
            plexamp_plugin = get_media_plugin('plexamp', plexamp_config)
            print(f"Plexamp initialisé sur {plexamp_config.get('host')}:{plexamp_config.get('port')}")
        except Exception as e:
            print(f"Erreur initialisation Plexamp: {e}")
            plexamp_plugin = None
    else:
        plexamp_plugin = None


@app.route('/api/plexamp/status')
def api_plexamp_status():
    """Retourne l'état actuel de lecture Plexamp"""
    global plexamp_plugin
    
    if not plexamp_plugin:
        return jsonify({"enabled": False, "error": "Plexamp non configuré"})
    
    now_playing = plexamp_plugin.get_now_playing()
    
    if not now_playing:
        return jsonify({"enabled": True, "playing": False, "state": "unknown"})
    
    # Ajouter l'URL complète de l'artwork
    if now_playing.get('thumb'):
        now_playing['artwork_url'] = plexamp_plugin.get_artwork_url(now_playing['thumb'])
    
    now_playing['enabled'] = True
    return jsonify(now_playing)


@app.route('/api/plexamp/play', methods=['POST'])
def api_plexamp_play():
    """Reprend la lecture"""
    global plexamp_plugin
    
    if not plexamp_plugin:
        return jsonify({"success": False, "error": "Plexamp non configuré"}), 400
    
    success = plexamp_plugin.play()
    return jsonify({"success": success})


@app.route('/api/plexamp/pause', methods=['POST'])
def api_plexamp_pause():
    """Met en pause"""
    global plexamp_plugin
    
    if not plexamp_plugin:
        return jsonify({"success": False, "error": "Plexamp non configuré"}), 400
    
    success = plexamp_plugin.pause()
    return jsonify({"success": success})


@app.route('/api/plexamp/playpause', methods=['POST'])
def api_plexamp_playpause():
    """Toggle play/pause"""
    global plexamp_plugin
    
    if not plexamp_plugin:
        return jsonify({"success": False, "error": "Plexamp non configuré"}), 400
    
    success = plexamp_plugin.play_pause()
    return jsonify({"success": success})


@app.route('/api/plexamp/next', methods=['POST'])
def api_plexamp_next():
    """Piste suivante"""
    global plexamp_plugin
    
    if not plexamp_plugin:
        return jsonify({"success": False, "error": "Plexamp non configuré"}), 400
    
    success = plexamp_plugin.next_track()
    return jsonify({"success": success})


@app.route('/api/plexamp/prev', methods=['POST'])
def api_plexamp_prev():
    """Piste précédente"""
    global plexamp_plugin
    
    if not plexamp_plugin:
        return jsonify({"success": False, "error": "Plexamp non configuré"}), 400
    
    success = plexamp_plugin.prev_track()
    return jsonify({"success": success})


@app.route('/api/plexamp/seek', methods=['POST'])
def api_plexamp_seek():
    """Aller à une position"""
    global plexamp_plugin
    
    if not plexamp_plugin:
        return jsonify({"success": False, "error": "Plexamp non configuré"}), 400
    
    data = request.get_json()
    position = data.get('position', 0)
    
    success = plexamp_plugin.seek(int(position))
    return jsonify({"success": success})


@app.route('/api/plexamp/config', methods=['GET'])
def api_plexamp_config_get():
    """Récupère la config Plexamp"""
    config = load_config()
    plexamp_config = config.get('media', {}).get('plexamp', {})
    # Ne pas renvoyer le token complet pour la sécurité
    safe_config = {
        'enabled': plexamp_config.get('enabled', False),
        'host': plexamp_config.get('host', '127.0.0.1'),
        'port': plexamp_config.get('port', 32400),
        'has_token': bool(plexamp_config.get('token'))
    }
    return jsonify(safe_config)


@app.route('/api/plexamp/config', methods=['POST'])
def api_plexamp_config_save():
    """Sauvegarde la config Plexamp"""
    global plexamp_plugin
    
    data = request.get_json()
    config = load_config()
    
    if 'media' not in config:
        config['media'] = {}
    
    config['media']['plexamp'] = {
        'enabled': data.get('enabled', False),
        'host': data.get('host', '127.0.0.1'),
        'port': data.get('port', 32400),
        'token': data.get('token', '')
    }
    
    save_config(config)
    
    # Réinitialiser le plugin
    init_plexamp()
    
    return jsonify({"success": True, "message": "Configuration Plexamp sauvegardée"})


@app.route('/api/plexamp/test', methods=['POST'])
def api_plexamp_test():
    """Teste la connexion Plexamp"""
    data = request.get_json()
    
    try:
        test_plugin = get_media_plugin('plexamp', data)
        result = test_plugin.test_connection()
        return jsonify(result)
    except Exception as e:
        return jsonify({"success": False, "error": str(e)})


# ==================== Démarrage ====================

if __name__ == '__main__':
    # Initialiser les plugins
    init_plugin()
    init_plexamp()
    
    # Démarrer le thread d'historique
    history_thread = Thread(target=update_history_loop, daemon=True)
    history_thread.start()
    
    config = load_config()
    plugin_id = config.get('active_plugin', 'librehardwaremonitor')
    plugin_config = config.get('plugins', {}).get(plugin_id, {})
    plexamp_config = config.get('media', {}).get('plexamp', {})
    
    print("=" * 60)
    print("PC Monitor - Serveur de monitoring v1.2.2")
    print("=" * 60)
    print(f"Plugin actif: {plugin_id}")
    print(f"Hôte: {plugin_config.get('host', '127.0.0.1')}")
    print(f"Port: {plugin_config.get('port', 'N/A')}")
    print("-" * 60)
    if plexamp_config.get('enabled'):
        print(f"Plexamp: activé ({plexamp_config.get('host')}:{plexamp_config.get('port')})")
    else:
        print("Plexamp: désactivé")
    print("-" * 60)
    print(f"Admin: http://localhost:5000/admin")
    print(f"Dashboard: http://localhost:5000/dashboard")
    print("=" * 60)
    
    app.run(host='0.0.0.0', port=5000, debug=True)
