import uuid

from flask import Blueprint, Response, jsonify, request

from hiveos.api.context import get_core_from_request
from hiveos import config as config_module
from hiveos.intelligence.model_routing_artifacts import (
    create_model_routing_artifact,
    get_model_routing_artifact,
    list_model_routing_artifacts,
)
from hiveos.intelligence.model_routing import build_model_routing_recommendation
from hiveos.intelligence.tracing import (
    build_trace_event,
    emit_trace,
    read_trace_events,
    read_trace_events_ndjson,
)


traces_bp = Blueprint("traces", __name__)


@traces_bp.route("/trace_events", methods=["GET"])
def trace_events():
    try:
        _ = get_core_from_request()
    except PermissionError as e:
        return jsonify({"error": str(e)}), 403

    limit = request.args.get("limit", default=200, type=int)
    if limit > 1000:
        limit = 1000

    filters = {
        "run_id": request.args.get("run_id"),
        "agent_id": request.args.get("agent_id"),
        "event_type": request.args.get("event_type"),
        "outcome": request.args.get("outcome"),
        "task_id": request.args.get("task_id"),
        "chunk_id": request.args.get("chunk_id"),
        "zone_id": request.args.get("zone_id"),
        "model_provider": request.args.get("model_provider"),
        "model_name": request.args.get("model_name"),
        "quality_status": request.args.get("quality_status"),
    }
    events = read_trace_events(limit=limit, filters=filters)
    return jsonify({"events": events, "count": len(events), "limit": limit})


@traces_bp.route("/trace_events_export", methods=["GET"])
def trace_events_export():
    try:
        _ = get_core_from_request()
    except PermissionError as e:
        return jsonify({"error": str(e)}), 403

    limit = request.args.get("limit", default=1000, type=int)
    max_limit = max(1, int(config_module.TRACE_EXPORT_MAX_LIMIT))
    if limit > max_limit:
        limit = max_limit
    if limit <= 0:
        limit = 1

    filters = {
        "run_id": request.args.get("run_id"),
        "agent_id": request.args.get("agent_id"),
        "event_type": request.args.get("event_type"),
        "outcome": request.args.get("outcome"),
        "task_id": request.args.get("task_id"),
        "chunk_id": request.args.get("chunk_id"),
        "zone_id": request.args.get("zone_id"),
        "model_provider": request.args.get("model_provider"),
        "model_name": request.args.get("model_name"),
        "quality_status": request.args.get("quality_status"),
    }
    body = read_trace_events_ndjson(limit=limit, filters=filters)
    return Response(body, mimetype="application/x-ndjson")


@traces_bp.route("/model_routing_recommendation", methods=["GET"])
def model_routing_recommendation():
    try:
        _ = get_core_from_request()
    except PermissionError as e:
        return jsonify({"error": str(e)}), 403

    limit = request.args.get("limit", default=2000, type=int)
    if limit > 5000:
        limit = 5000
    if limit <= 0:
        limit = 1

    min_samples = request.args.get("min_samples", default=2, type=int)
    if min_samples <= 0:
        min_samples = 1

    routes_arg = str(request.args.get("routes") or "").strip()
    route_classes = [item.strip() for item in routes_arg.split(",") if item.strip()] if routes_arg else None

    events = read_trace_events(limit=limit, filters={})
    artifact = build_model_routing_recommendation(
        events=events,
        route_classes=route_classes,
        min_samples=min_samples,
    )
    artifact["event_window_count"] = len(events)
    artifact["limit"] = limit
    return jsonify(artifact)


@traces_bp.route("/model_routing_profile", methods=["GET"])
def model_routing_profile():
    try:
        _ = get_core_from_request()
    except PermissionError as e:
        return jsonify({"error": str(e)}), 403
    return jsonify(config_module.get_ai_route_model_profile())


@traces_bp.route("/model_routing_profile_apply", methods=["POST"])
def model_routing_profile_apply():
    try:
        _ = get_core_from_request()
    except PermissionError as e:
        return jsonify({"error": str(e)}), 403

    data = request.get_json(silent=True) or {}
    apply_change = bool(data.get("apply", False))
    default_model = data.get("default_model")
    route_models = dict(data.get("route_models") or {})
    artifact_id = str(data.get("artifact_id") or "").strip()

    artifact = data.get("artifact") if isinstance(data.get("artifact"), dict) else {}
    if artifact_id and not artifact:
        stored = get_model_routing_artifact(artifact_id)
        if not stored:
            return jsonify({"error": "artifact_not_found", "artifact_id": artifact_id}), 404
        artifact = dict(stored.get("artifact") or {})
    for item in list(artifact.get("recommendations") or []):
        if not isinstance(item, dict):
            continue
        route_class = str(item.get("route_class") or "").strip().lower()
        winner = item.get("winner") or {}
        model_name = str((winner.get("name") if isinstance(winner, dict) else "") or "").strip()
        if route_class and model_name and route_class not in route_models:
            route_models[route_class] = model_name

    before = config_module.get_ai_route_model_profile()
    preview = {
        "default_model": str(default_model).strip() if default_model is not None else before.get("default_model"),
        "routes": dict(before.get("routes") or {}),
    }
    for route, model in route_models.items():
        route_key = str(route or "").strip().lower()
        if route_key in preview["routes"]:
            preview["routes"][route_key] = str(model or "").strip()

    run_id = f"model-routing:profile:{request.headers.get('X-Session-ID') or 'none'}:{uuid.uuid4().hex[:8]}"
    actor = {
        "user_id": request.headers.get("X-User-ID"),
        "session_id": request.headers.get("X-Session-ID"),
    }
    emit_trace(
        build_trace_event(
            event_type="model_routing_profile_reviewed",
            run_id=run_id,
            outcome="success",
            payload={
                "apply_requested": apply_change,
                "artifact_id": artifact_id or None,
                "before": before,
                "preview": preview,
                "actor": actor,
            },
            agent_id=actor.get("user_id"),
        )
    )

    if not apply_change:
        return jsonify({"applied": False, "before": before, "preview": preview})

    after = config_module.apply_ai_route_model_profile(default_model=default_model, route_models=route_models)
    emit_trace(
        build_trace_event(
            event_type="model_routing_profile_applied",
            run_id=run_id,
            outcome="success",
            payload={
                "artifact_id": artifact_id or None,
                "before": before,
                "after": after,
                "actor": actor,
            },
            agent_id=actor.get("user_id"),
        )
    )
    return jsonify({"applied": True, "before": before, "after": after})


@traces_bp.route("/model_routing_artifacts", methods=["GET"])
def model_routing_artifacts_get():
    try:
        _ = get_core_from_request()
    except PermissionError as e:
        return jsonify({"error": str(e)}), 403

    artifact_id = str(request.args.get("artifact_id") or "").strip()
    if artifact_id:
        item = get_model_routing_artifact(artifact_id)
        if not item:
            return jsonify({"error": "artifact_not_found"}), 404
        return jsonify(item)

    limit = request.args.get("limit", default=20, type=int)
    if limit > 100:
        limit = 100
    if limit <= 0:
        limit = 1
    items = list_model_routing_artifacts(limit=limit)
    return jsonify({"artifacts": items, "count": len(items), "limit": limit})


@traces_bp.route("/model_routing_artifacts", methods=["POST"])
def model_routing_artifacts_post():
    try:
        _ = get_core_from_request()
    except PermissionError as e:
        return jsonify({"error": str(e)}), 403

    data = request.get_json(silent=True) or {}
    limit = int(data.get("limit") or 2000)
    if limit > 5000:
        limit = 5000
    if limit <= 0:
        limit = 1
    min_samples = int(data.get("min_samples") or 2)
    if min_samples <= 0:
        min_samples = 1
    route_classes = data.get("routes")
    if isinstance(route_classes, list):
        route_classes = [str(item).strip() for item in route_classes if str(item).strip()]
    else:
        route_classes = None

    events = read_trace_events(limit=limit, filters={})
    artifact = build_model_routing_recommendation(
        events=events,
        route_classes=route_classes,
        min_samples=min_samples,
    )
    artifact["event_window_count"] = len(events)
    artifact["limit"] = limit
    stored = create_model_routing_artifact(
        artifact=artifact,
        meta={
            "created_by_user": request.headers.get("X-User-ID"),
            "session_id": request.headers.get("X-Session-ID"),
        },
    )
    emit_trace(
        build_trace_event(
            event_type="model_routing_artifact_created",
            run_id=f"model-routing:artifact:{stored.get('artifact_id')}",
            outcome="success",
            payload={
                "artifact_id": stored.get("artifact_id"),
                "event_window_count": artifact.get("event_window_count"),
                "routes_evaluated": artifact.get("routes_evaluated"),
            },
            agent_id=request.headers.get("X-User-ID"),
        )
    )
    return jsonify(stored), 201
