"""Relations app action endpoints."""
from __future__ import annotations

from quart import Blueprint, g, jsonify, request

from shared.infrastructure.actions import ACTION_HEADER


def register() -> Blueprint:
    bp = Blueprint("actions", __name__, url_prefix="/internal/actions")

    @bp.before_request
    async def _require_action_header():
        if not request.headers.get(ACTION_HEADER):
            return jsonify({"error": "forbidden"}), 403
        from shared.infrastructure.internal_auth import validate_internal_request
        if not validate_internal_request():
            return jsonify({"error": "forbidden"}), 403

    _handlers: dict[str, object] = {}

    @bp.post("/<action_name>")
    async def handle_action(action_name: str):
        handler = _handlers.get(action_name)
        if handler is None:
            return jsonify({"error": "unknown action"}), 404
        try:
            result = await handler()
            return jsonify(result)
        except Exception as exc:
            import logging
            logging.getLogger(__name__).exception("Action %s failed", action_name)
            return jsonify({"error": str(exc)}), 500

    # --- attach-child ---
    async def _attach_child():
        """Create or revive a ContainerRelation."""
        from shared.services.relationships import attach_child

        data = await request.get_json(force=True)
        rel  = await attach_child(
            g.s,
            parent_type=data["parent_type"],
            parent_id=data["parent_id"],
            child_type=data["child_type"],
            child_id=data["child_id"],
            label=data.get("label"),
            sort_order=data.get("sort_order"),
            relation_type=data.get("relation_type"),
            metadata=data.get("metadata"),
        )
        return {
            "id":          rel.id,
            "parent_type": rel.parent_type,
            "parent_id":   rel.parent_id,
            "child_type":  rel.child_type,
            "child_id":    rel.child_id,
            "sort_order":  rel.sort_order,
            "relation_type": rel.relation_type,
        }

    _handlers["attach-child"] = _attach_child

    # --- detach-child ---
    async def _detach_child():
        """Soft-delete a ContainerRelation."""
        from shared.services.relationships import detach_child

        data    = await request.get_json(force=True)
        deleted = await detach_child(
            g.s,
            parent_type=data["parent_type"],
            parent_id=data["parent_id"],
            child_type=data["child_type"],
            child_id=data["child_id"],
            relation_type=data.get("relation_type"),
        )
        return {"deleted": deleted}

    _handlers["detach-child"] = _detach_child

    # --- relate (registry-aware) ---
    async def _relate():
        """Create a typed relation with registry validation and cardinality enforcement."""
        from shared.services.relationships import attach_child, get_children
        from shared.sx.relations import get_relation

        data = await request.get_json(force=True)
        rel_type = data.get("relation_type")
        if not rel_type:
            return {"error": "relation_type is required"}, 400

        defn = get_relation(rel_type)
        if defn is None:
            return {"error": f"unknown relation_type: {rel_type}"}, 400

        from_id = data["from_id"]
        to_id = data["to_id"]

        # Cardinality enforcement
        if defn.cardinality == "one-to-one":
            existing = await get_children(
                g.s,
                parent_type=defn.from_type,
                parent_id=from_id,
                child_type=defn.to_type,
                relation_type=rel_type,
            )
            if existing:
                return {"error": "one-to-one relation already exists", "existing_id": existing[0].child_id}, 409

        rel = await attach_child(
            g.s,
            parent_type=defn.from_type,
            parent_id=from_id,
            child_type=defn.to_type,
            child_id=to_id,
            label=data.get("label"),
            sort_order=data.get("sort_order"),
            relation_type=rel_type,
            metadata=data.get("metadata"),
        )
        return {
            "id": rel.id,
            "relation_type": rel.relation_type,
            "parent_type": rel.parent_type,
            "parent_id": rel.parent_id,
            "child_type": rel.child_type,
            "child_id": rel.child_id,
            "sort_order": rel.sort_order,
        }

    _handlers["relate"] = _relate

    # --- unrelate (registry-aware) ---
    async def _unrelate():
        """Remove a typed relation with registry validation."""
        from shared.services.relationships import detach_child
        from shared.sx.relations import get_relation

        data = await request.get_json(force=True)
        rel_type = data.get("relation_type")
        if not rel_type:
            return {"error": "relation_type is required"}, 400

        defn = get_relation(rel_type)
        if defn is None:
            return {"error": f"unknown relation_type: {rel_type}"}, 400

        deleted = await detach_child(
            g.s,
            parent_type=defn.from_type,
            parent_id=data["from_id"],
            child_type=defn.to_type,
            child_id=data["to_id"],
            relation_type=rel_type,
        )
        return {"deleted": deleted}

    _handlers["unrelate"] = _unrelate

    # --- can-relate (pre-flight check) ---
    async def _can_relate():
        """Check if a relation can be created (cardinality, registry validation)."""
        from shared.services.relationships import get_children
        from shared.sx.relations import get_relation

        data = await request.get_json(force=True)
        rel_type = data.get("relation_type")
        if not rel_type:
            return {"error": "relation_type is required"}, 400

        defn = get_relation(rel_type)
        if defn is None:
            return {"allowed": False, "reason": f"unknown relation_type: {rel_type}"}

        from_id = data["from_id"]

        if defn.cardinality == "one-to-one":
            existing = await get_children(
                g.s,
                parent_type=defn.from_type,
                parent_id=from_id,
                child_type=defn.to_type,
                relation_type=rel_type,
            )
            if existing:
                return {"allowed": False, "reason": "one-to-one relation already exists"}

        return {"allowed": True}

    _handlers["can-relate"] = _can_relate

    return bp
