from flask import request

from hiveos.config import ENFORCE_USER_CAPABILITIES, USER_CAPABILITIES_HEADER
from hiveos.intelligence.tracing import build_trace_event, emit_trace, now_iso
from hiveos.security.authorization import authorize_action, parse_capabilities
from hiveos.session_manager import session_manager


def build_action_run_id(action, user_id=None, session_id=None):
    resolved_session = session_id if session_id is not None else request.headers.get("X-Session-ID")
    resolved_user = user_id if user_id is not None else request.headers.get("X-User-ID")
    return f"policy:{action}:{resolved_session or 'none'}:{resolved_user or 'none'}"


def emit_action_applied(action, resource_type, resource_id=None, user_id=None, session_id=None, payload=None):
    event_payload = {"action": action, "resource_type": resource_type, "resource_id": resource_id}
    if payload:
        event_payload.update(payload)
    emit_trace(
        build_trace_event(
            event_type="action_applied",
            run_id=build_action_run_id(action, user_id=user_id, session_id=session_id),
            outcome="success",
            payload=event_payload,
            task_id=(resource_id if resource_type == "task" else None),
            zone_id=(resource_id if resource_type == "zone" else None),
        )
    )


def emit_action_failed(action, resource_type, reason, resource_id=None, user_id=None, session_id=None, payload=None):
    event_payload = {
        "action": action,
        "resource_type": resource_type,
        "resource_id": resource_id,
        "reason": str(reason),
    }
    if payload:
        event_payload.update(payload)
    emit_trace(
        build_trace_event(
            event_type="action_failed",
            run_id=build_action_run_id(action, user_id=user_id, session_id=session_id),
            outcome="failed",
            payload=event_payload,
            task_id=(resource_id if resource_type == "task" else None),
            zone_id=(resource_id if resource_type == "zone" else None),
        )
    )


def get_core_from_request():
    session_id = request.headers.get("X-Session-ID")
    user_id = request.headers.get("X-User-ID")

    if not session_id or not user_id:
        raise PermissionError("Missing session or user ID")

    session = session_manager.get_session_record(session_id)
    if not session or session.get("user_id") != user_id:
        raise PermissionError("Unauthorized or missing session")

    return session["core"]


def authorize_core_action(action, resource_type, resource_id=None):
    session_id = request.headers.get("X-Session-ID")
    user_id = request.headers.get("X-User-ID")
    caps_raw = request.headers.get(USER_CAPABILITIES_HEADER)
    granted_caps = parse_capabilities(caps_raw)
    run_id = build_action_run_id(action, user_id=user_id, session_id=session_id)

    emit_trace(
        build_trace_event(
            event_type="action_requested",
            run_id=run_id,
            outcome="success",
            payload={
                "action": action,
                "resource_type": resource_type,
                "resource_id": resource_id,
                "actor": {"user_id": user_id, "session_id": session_id, "capabilities": granted_caps},
                "requested_at": now_iso(),
            },
            task_id=(resource_id if resource_type == "task" else None),
            zone_id=(resource_id if resource_type == "zone" else None),
        )
    )

    core = get_core_from_request()
    decision = authorize_action(action, granted_caps, enforce=ENFORCE_USER_CAPABILITIES)
    if not decision.allowed:
        emit_trace(
            build_trace_event(
                event_type="action_denied",
                run_id=run_id,
                outcome="denied",
                payload={
                    "action": action,
                    "resource_type": resource_type,
                    "resource_id": resource_id,
                    "reason": decision.reason,
                    "required_capabilities": list(decision.required_capabilities),
                    "granted_capabilities": list(decision.granted_capabilities),
                },
                task_id=(resource_id if resource_type == "task" else None),
                zone_id=(resource_id if resource_type == "zone" else None),
            )
        )
        raise PermissionError(f"Unauthorized action: {decision.reason}")

    emit_trace(
        build_trace_event(
            event_type="action_authorized",
            run_id=run_id,
            outcome="success",
            payload={
                "action": action,
                "resource_type": resource_type,
                "resource_id": resource_id,
                "required_capabilities": list(decision.required_capabilities),
                "granted_capabilities": list(decision.granted_capabilities),
                "reason": decision.reason,
            },
            task_id=(resource_id if resource_type == "task" else None),
            zone_id=(resource_id if resource_type == "zone" else None),
        )
    )
    return core


def authorize_user_action(action, resource_type, user_id, session_id=None, resource_id=None):
    caps_raw = request.headers.get(USER_CAPABILITIES_HEADER)
    granted_caps = parse_capabilities(caps_raw)
    run_id = build_action_run_id(action, user_id=user_id, session_id=session_id)

    emit_trace(
        build_trace_event(
            event_type="action_requested",
            run_id=run_id,
            outcome="success",
            payload={
                "action": action,
                "resource_type": resource_type,
                "resource_id": resource_id,
                "actor": {"user_id": user_id, "session_id": session_id, "capabilities": granted_caps},
                "requested_at": now_iso(),
            },
            task_id=(resource_id if resource_type == "task" else None),
            zone_id=(resource_id if resource_type == "zone" else None),
        )
    )

    decision = authorize_action(action, granted_caps, enforce=ENFORCE_USER_CAPABILITIES)
    if not decision.allowed:
        emit_trace(
            build_trace_event(
                event_type="action_denied",
                run_id=run_id,
                outcome="denied",
                payload={
                    "action": action,
                    "resource_type": resource_type,
                    "resource_id": resource_id,
                    "reason": decision.reason,
                    "required_capabilities": list(decision.required_capabilities),
                    "granted_capabilities": list(decision.granted_capabilities),
                },
                task_id=(resource_id if resource_type == "task" else None),
                zone_id=(resource_id if resource_type == "zone" else None),
            )
        )
        raise PermissionError(f"Unauthorized action: {decision.reason}")

    emit_trace(
        build_trace_event(
            event_type="action_authorized",
            run_id=run_id,
            outcome="success",
            payload={
                "action": action,
                "resource_type": resource_type,
                "resource_id": resource_id,
                "required_capabilities": list(decision.required_capabilities),
                "granted_capabilities": list(decision.granted_capabilities),
                "reason": decision.reason,
            },
            task_id=(resource_id if resource_type == "task" else None),
            zone_id=(resource_id if resource_type == "zone" else None),
        )
    )
