from flask import Blueprint, jsonify, request

from hiveos.api.context import authorize_core_action, emit_action_applied, emit_action_failed, get_core_from_request


terminal_bp = Blueprint("terminal", __name__)


@terminal_bp.route("/terminal_targets", methods=["GET"])
def terminal_targets():
    try:
        core = get_core_from_request()
    except PermissionError as e:
        return jsonify({"error": str(e)}), 403
    return jsonify({"targets": core.terminal_service.list_targets()})


@terminal_bp.route("/terminal_open", methods=["POST"])
def terminal_open():
    action = "terminal.open"
    try:
        core = authorize_core_action(action, resource_type="session")
    except PermissionError as e:
        return jsonify({"error": str(e)}), 403
    data = request.get_json(silent=True) or {}
    descriptor = {
        "target_id": data.get("target_id"),
        "target_type": data.get("target_type"),
        "session_id": request.headers.get("X-Session-ID"),
        "agent_id": data.get("agent_id"),
        "transport": data.get("transport"),
        "meta": data.get("meta"),
    }
    try:
        target = core.terminal_service.open_target(descriptor)
        emit_action_applied(
            action,
            resource_type="session",
            payload={"target_id": target["target_id"], "target_type": target["target_type"]},
        )
        return jsonify({"target": target}), 200
    except Exception as e:
        emit_action_failed(action, resource_type="session", reason=e)
        return jsonify({"error": str(e)}), 400


@terminal_bp.route("/terminal_close", methods=["POST"])
def terminal_close():
    action = "terminal.close"
    data = request.get_json(silent=True) or {}
    target_id = data.get("target_id")
    try:
        core = authorize_core_action(action, resource_type="session")
    except PermissionError as e:
        return jsonify({"error": str(e)}), 403
    if not target_id:
        return jsonify({"error": "Missing target_id"}), 400
    closed = core.terminal_service.close_target(str(target_id))
    if not closed:
        emit_action_failed(action, resource_type="session", reason="target_not_found", payload={"target_id": target_id})
        return jsonify({"error": "target_not_found"}), 404
    emit_action_applied(action, resource_type="session", payload={"target_id": target_id})
    return jsonify({"target_id": target_id, "closed": True}), 200


@terminal_bp.route("/terminal_clear", methods=["POST"])
def terminal_clear():
    action = "terminal.clear"
    data = request.get_json(silent=True) or {}
    target_id = data.get("target_id")
    try:
        core = authorize_core_action(action, resource_type="session")
    except PermissionError as e:
        return jsonify({"error": str(e)}), 403
    if not target_id:
        return jsonify({"error": "Missing target_id"}), 400
    cleared = core.terminal_service.clear_output(str(target_id))
    if not cleared:
        emit_action_failed(action, resource_type="session", reason="target_not_found", payload={"target_id": target_id})
        return jsonify({"error": "target_not_found"}), 404
    emit_action_applied(action, resource_type="session", payload={"target_id": target_id})
    return jsonify({"target_id": target_id, "cleared": True}), 200


@terminal_bp.route("/terminal_transform", methods=["POST"])
def terminal_transform():
    action = "terminal.transform"
    try:
        core = authorize_core_action(action, resource_type="session")
    except PermissionError as e:
        return jsonify({"error": str(e)}), 403
    data = request.get_json(silent=True) or {}
    target_id = data.get("target_id")
    module = data.get("module")
    if not target_id or not module:
        return jsonify({"error": "Missing target_id or module"}), 400
    try:
        updated = core.terminal_service.set_transform(
            target_id=str(target_id),
            module=str(module),
            config=data.get("config") or {},
        )
        emit_action_applied(
            action,
            resource_type="session",
            payload={"target_id": target_id, "module": module},
        )
        return jsonify({"target": updated}), 200
    except KeyError:
        emit_action_failed(action, resource_type="session", reason="target_not_found", payload={"target_id": target_id})
        return jsonify({"error": "target_not_found"}), 404
    except Exception as e:
        emit_action_failed(action, resource_type="session", reason=e, payload={"target_id": target_id, "module": module})
        return jsonify({"error": str(e)}), 400


@terminal_bp.route("/terminal_exec", methods=["POST"])
def terminal_exec():
    action = "terminal.exec"
    try:
        core = authorize_core_action(action, resource_type="session")
    except PermissionError as e:
        return jsonify({"error": str(e)}), 403
    data = request.get_json(silent=True) or {}
    target_id = data.get("target_id")
    command = data.get("command")
    if not target_id or not command:
        return jsonify({"error": "Missing target_id or command"}), 400
    try:
        result = core.terminal_service.run_command(
            target_id=str(target_id),
            command=str(command),
            cwd=data.get("cwd"),
            env=data.get("env"),
            timeout_sec=int(data.get("timeout_sec") or 30),
        )
        emit_action_applied(
            action,
            resource_type="session",
            payload={"target_id": target_id, "exit_code": result["exit_code"]},
        )
        return jsonify(result), 200
    except KeyError:
        emit_action_failed(action, resource_type="session", reason="target_not_found", payload={"target_id": target_id})
        return jsonify({"error": "target_not_found"}), 404
    except TimeoutError as e:
        emit_action_failed(action, resource_type="session", reason=e, payload={"target_id": target_id})
        return jsonify({"error": str(e)}), 408
    except Exception as e:
        emit_action_failed(action, resource_type="session", reason=e, payload={"target_id": target_id})
        return jsonify({"error": str(e)}), 500
