from models.models import Client
# Neue Route: Liefert alle Gruppen mit zugehörigen Clients und deren Alive-Status

from server.database import Session
from models.models import ClientGroup
from flask import Blueprint, request, jsonify
from server.permissions import admin_or_higher, require_role
from sqlalchemy import func
import sys
import os
from datetime import datetime, timedelta, timezone

sys.path.append('/workspace')

groups_bp = Blueprint("groups", __name__, url_prefix="/api/groups")


def get_grace_period():
    """Wählt die Grace-Periode abhängig von ENV.
    
    Clients send heartbeats every ~65s. Grace period allows 2 missed
    heartbeats plus safety margin before marking offline.
    """
    env = os.environ.get("ENV", "production").lower()
    if env == "development" or env == "dev":
        return int(os.environ.get("HEARTBEAT_GRACE_PERIOD_DEV", "180"))
    return int(os.environ.get("HEARTBEAT_GRACE_PERIOD_PROD", "170"))


def _to_utc(dt: datetime) -> datetime:
    if dt is None:
        return None
    if dt.tzinfo is None:
        return dt.replace(tzinfo=timezone.utc)
    return dt.astimezone(timezone.utc)


def is_client_alive(last_alive, is_active):
    """Berechnet, ob ein Client als alive gilt."""
    if not last_alive or not is_active:
        return False
    grace_period = get_grace_period()
    # last_alive kann ein String oder datetime sein
    if isinstance(last_alive, str):
        last_alive_str = last_alive[:-
                                    1] if last_alive.endswith('Z') else last_alive
        try:
            last_alive_dt = datetime.fromisoformat(last_alive_str)
        except Exception:
            return False
    else:
        last_alive_dt = last_alive
    # Vergleiche immer in UTC und mit tz-aware Datetimes
    last_alive_utc = _to_utc(last_alive_dt)
    now_utc = datetime.now(timezone.utc)
    return (now_utc - last_alive_utc) <= timedelta(seconds=grace_period)


@groups_bp.route("", methods=["POST"])
@admin_or_higher
def create_group():
    data = request.get_json()
    name = data.get("name")
    if not name or not name.strip():
        return jsonify({"error": "Gruppenname erforderlich"}), 400

    session = Session()
    if session.query(ClientGroup).filter_by(name=name).first():
        session.close()
        return jsonify({"error": "Gruppe existiert bereits"}), 409

    group = ClientGroup(name=name, is_active=True)
    session.add(group)
    session.commit()
    result = {
        "id": group.id,
        "name": group.name,
        "created_at": group.created_at.isoformat() if group.created_at else None,
        "is_active": group.is_active,
    }
    session.close()
    return jsonify(result), 201


@groups_bp.route("", methods=["GET"])
def get_groups():
    session = Session()
    groups = session.query(ClientGroup).all()
    result = [
        {
            "id": g.id,
            "name": g.name,
            "created_at": g.created_at.isoformat() if g.created_at else None,
            "is_active": g.is_active,
        }
        for g in groups
    ]
    session.close()
    return jsonify(result)


@groups_bp.route("/<int:group_id>", methods=["PUT"])
@admin_or_higher
def update_group(group_id):
    data = request.get_json()
    session = Session()
    group = session.query(ClientGroup).filter_by(id=group_id).first()
    if not group:
        session.close()
        return jsonify({"error": "Gruppe nicht gefunden"}), 404
    if "name" in data:
        group.name = data["name"]
    if "is_active" in data:
        group.is_active = bool(data["is_active"])
    session.commit()
    result = {
        "id": group.id,
        "name": group.name,
        "created_at": group.created_at.isoformat() if group.created_at else None,
        "is_active": group.is_active,
    }
    session.close()
    return jsonify(result)


@groups_bp.route("/<int:group_id>", methods=["DELETE"])
@admin_or_higher
def delete_group(group_id):
    session = Session()
    group = session.query(ClientGroup).filter_by(id=group_id).first()
    if not group:
        session.close()
        return jsonify({"error": "Gruppe nicht gefunden"}), 404
    session.delete(group)
    session.commit()
    session.close()
    return jsonify({"success": True})


@groups_bp.route("/byname/<string:group_name>", methods=["DELETE"])
@admin_or_higher
def delete_group_by_name(group_name):
    session = Session()
    group = session.query(ClientGroup).filter_by(name=group_name).first()
    if not group:
        session.close()
        return jsonify({"error": "Gruppe nicht gefunden"}), 404
    session.delete(group)
    session.commit()
    session.close()
    return jsonify({"success": True})


@groups_bp.route("/byname/<string:old_name>", methods=["PUT"])
@admin_or_higher
def rename_group_by_name(old_name):
    data = request.get_json()
    new_name = data.get("newName")
    if not new_name or not new_name.strip():
        return jsonify({"error": "Neuer Name erforderlich"}), 400

    session = Session()
    group = session.query(ClientGroup).filter_by(name=old_name).first()
    if not group:
        session.close()
        return jsonify({"error": "Gruppe nicht gefunden"}), 404

    # Prüfe, ob der neue Name schon existiert
    if session.query(ClientGroup).filter(func.binary(ClientGroup.name) == new_name).first():
        session.close()
        return jsonify({"error": f'Gruppe mit dem Namen "{new_name}" existiert bereits', "duplicate_name": new_name}), 409

    group.name = new_name
    session.commit()
    result = {
        "id": group.id,
        "name": group.name,
        "created_at": group.created_at.isoformat() if group.created_at else None,
        "is_active": group.is_active,
    }
    session.close()
    return jsonify(result)


@groups_bp.route("/with_clients", methods=["GET"])
def get_groups_with_clients():
    session = Session()
    groups = session.query(ClientGroup).all()
    result = []
    for g in groups:
        clients = session.query(Client).filter_by(group_id=g.id).all()
        client_list = []
        for c in clients:
            client_list.append({
                "uuid": c.uuid,
                "description": c.description,
                "ip": c.ip,
                "last_alive": c.last_alive.isoformat() if c.last_alive else None,
                "is_active": c.is_active,
                "is_alive": is_client_alive(c.last_alive, c.is_active),
            })
        result.append({
            "id": g.id,
            "name": g.name,
            "created_at": g.created_at.isoformat() if g.created_at else None,
            "is_active": g.is_active,
            "clients": client_list,
        })
    session.close()
    return jsonify(result)


@groups_bp.route("/order", methods=["GET"])
def get_group_order():
    """Retrieve the saved group order from system settings."""
    from models.models import SystemSetting
    session = Session()
    try:
        setting = session.query(SystemSetting).filter_by(key='group_order').first()
        if setting and setting.value:
            import json
            order = json.loads(setting.value)
            return jsonify({"order": order})
        return jsonify({"order": None})
    except Exception as e:
        print(f"Error loading group order: {e}")
        return jsonify({"order": None})
    finally:
        session.close()


@groups_bp.route("/order", methods=["POST"])
@require_role('admin')
def save_group_order():
    """Save the custom group order to system settings."""
    from models.models import SystemSetting
    session = Session()
    try:
        data = request.get_json()
        order = data.get('order')
        
        if not order or not isinstance(order, list):
            return jsonify({"success": False, "error": "Invalid order data"}), 400
        
        import json
        order_json = json.dumps(order)
        
        setting = session.query(SystemSetting).filter_by(key='group_order').first()
        if setting:
            setting.value = order_json
        else:
            setting = SystemSetting(key='group_order', value=order_json)
            session.add(setting)
        
        session.commit()
        return jsonify({"success": True})
    except Exception as e:
        session.rollback()
        print(f"Error saving group order: {e}")
        return jsonify({"success": False, "error": str(e)}), 500
    finally:
        session.close()
