"""Views & Visualization — REST API endpoints.

API version: v1
Base path: /api/v1/visualization/
"""

from __future__ import annotations

from rest_framework import status
from rest_framework.decorators import (
    api_view,
    authentication_classes,
    permission_classes,
)
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response

from simorgh.apps.visualization import selectors, services
from simorgh.apps.visualization.registry import (
    list_chart_types,
    list_view_types,
    list_widget_types,
    list_widget_types_by_kind,
)
from simorgh.core.context import current_request_context


def _ctx(request: Request):
    """Extract request-scoped context."""
    ctx = current_request_context()
    return {
        "tenant_id": ctx.tenant.pk if ctx.tenant else None,
        "organization_node_id": next(iter(ctx.org_node_ids)) if ctx.org_node_ids else None,
        "user_id": request.user.id,
    }


# ═════════════════════════════════════════════════════════════════════════════
# Registry endpoints (read-only, no tenant scope required for type metadata)
# ═════════════════════════════════════════════════════════════════════════════

@api_view(["GET"])
@authentication_classes([])  # public metadata
@permission_classes([])
def view_types_list(request: Request) -> Response:
    """List all registered view types."""
    types = list_view_types()
    data = [
        {
            "kind": t.kind,
            "label_key": t.label_key,
            "description": t.description,
            "icon": t.icon,
            "supports_custom_config": t.supports_custom_config,
            "supports_saved_views": t.supports_saved_views,
            "supports_filters": t.supports_filters,
            "supports_export": t.supports_export,
            "supports_grouping": t.supports_grouping,
            "config_schema": t.config_schema,
        }
        for t in types
    ]
    return Response(data)


@api_view(["GET"])
@authentication_classes([])
@permission_classes([])
def chart_types_list(request: Request) -> Response:
    """List all registered chart types."""
    types = list_chart_types()
    data = [
        {"kind": t.kind, "label_key": t.label_key, "description": t.description, "icon": t.icon}
        for t in types
    ]
    return Response(data)


@api_view(["GET"])
@authentication_classes([])
@permission_classes([])
def widget_types_list(request: Request) -> Response:
    """List all registered widget types."""
    kind_filter = request.query_params.get("kind")
    types = list_widget_types_by_kind(kind_filter) if kind_filter else list_widget_types()
    data = [
        {
            "name": t.name,
            "kind": t.kind,
            "label_key": t.label_key,
            "description": t.description,
            "icon": t.icon,
            "default_cols": t.default_cols,
            "module": t.module,
        }
        for t in types
    ]
    return Response(data)


# ═════════════════════════════════════════════════════════════════════════════
# View Configuration CRUD
# ═════════════════════════════════════════════════════════════════════════════

@api_view(["GET"])
@permission_classes([IsAuthenticated])
def view_configurations_list(request: Request) -> Response:
    """List view configurations for the current tenant."""
    c = _ctx(request)
    entity = request.query_params.get("entity")
    view_type = request.query_params.get("view_type")
    qs = selectors.get_view_configurations(
        tenant_id=c["tenant_id"],
        entity_name=entity,
        view_type=view_type,
    )
    data = [
        {
            "id": v.pk,
            "public_id": str(v.public_id),
            "name": v.name,
            "entity_name": v.entity_name,
            "view_type": v.view_type,
            "config": v.config,
            "is_default": v.is_default,
            "is_system": v.is_system,
            "visibility": v.visibility,
            "sort_order": v.sort_order,
            "created_at": v.created_at.isoformat() if v.created_at else None,
            "updated_at": v.updated_at.isoformat() if v.updated_at else None,
        }
        for v in qs
    ]
    return Response(data)


@api_view(["POST"])
@permission_classes([IsAuthenticated])
def view_configurations_create(request: Request) -> Response:
    """Create a new view configuration."""
    c = _ctx(request)
    view = services.create_view_configuration(
        tenant_id=c["tenant_id"],
        organization_node_id=c["organization_node_id"],
        created_by_id=c["user_id"],
        entity_name=request.data["entity_name"],
        view_type=request.data["view_type"],
        name=request.data["name"],
        config=request.data.get("config"),
        is_default=request.data.get("is_default", False),
        visibility=request.data.get("visibility", "private"),
    )
    return Response(
        {
            "id": view.pk,
            "public_id": str(view.public_id),
            "name": view.name,
            "entity_name": view.entity_name,
            "view_type": view.view_type,
            "config": view.config,
            "is_default": view.is_default,
            "is_system": view.is_system,
            "visibility": view.visibility,
            "created_at": view.created_at.isoformat(),
        },
        status=status.HTTP_201_CREATED,
    )


@api_view(["GET"])
@permission_classes([IsAuthenticated])
def view_configurations_detail(request: Request, view_id: int) -> Response:
    """Get a single view configuration."""
    c = _ctx(request)
    view = selectors.get_view_configuration(tenant_id=c["tenant_id"], view_id=view_id)
    filters = selectors.get_view_filters(tenant_id=c["tenant_id"], view_id=view_id)
    groupings = selectors.get_view_groupings(tenant_id=c["tenant_id"], view_id=view_id)

    return Response(
        {
            "id": view.pk,
            "public_id": str(view.public_id),
            "name": view.name,
            "entity_name": view.entity_name,
            "view_type": view.view_type,
            "config": view.config,
            "is_default": view.is_default,
            "is_system": view.is_system,
            "visibility": view.visibility,
            "sort_order": view.sort_order,
            "created_at": view.created_at.isoformat() if view.created_at else None,
            "updated_at": view.updated_at.isoformat() if view.updated_at else None,
            "filters": [
                {
                    "id": f.pk,
                    "public_id": str(f.public_id),
                    "name": f.name,
                    "filter_config": f.filter_config,
                    "is_default": f.is_default,
                }
                for f in filters
            ],
            "groupings": [
                {
                    "id": g.pk,
                    "field_name": g.field_name,
                    "label_key": g.label_key,
                    "color": g.color,
                    "sort_order": g.sort_order,
                }
                for g in groupings
            ],
        },
    )


@api_view(["PUT", "PATCH"])
@permission_classes([IsAuthenticated])
def view_configurations_update(request: Request, view_id: int) -> Response:
    """Update a view configuration."""
    c = _ctx(request)
    view = services.update_view_configuration(
        view_id=view_id,
        updated_by_id=c["user_id"],
        name=request.data.get("name"),
        config=request.data.get("config"),
        is_default=request.data.get("is_default"),
        visibility=request.data.get("visibility"),
    )
    return Response(
        {
            "id": view.pk,
            "public_id": str(view.public_id),
            "name": view.name,
            "entity_name": view.entity_name,
            "view_type": view.view_type,
            "config": view.config,
            "is_default": view.is_default,
            "visibility": view.visibility,
            "updated_at": view.updated_at.isoformat(),
        },
    )


@api_view(["DELETE"])
@permission_classes([IsAuthenticated])
def view_configurations_delete(request: Request, view_id: int) -> Response:
    """Delete a view configuration."""
    services.delete_view_configuration(view_id=view_id)
    return Response(status=status.HTTP_204_NO_CONTENT)


@api_view(["POST"])
@permission_classes([IsAuthenticated])
def view_configurations_set_default(request: Request, view_id: int) -> Response:
    """Set a view as the default for its entity."""
    view = services.set_default_view(
        view_id=view_id,
        entity_name=request.data.get("entity_name", ""),
    )
    return Response({"id": view.pk, "is_default": view.is_default})


# ═════════════════════════════════════════════════════════════════════════════
# View Filters
# ═════════════════════════════════════════════════════════════════════════════

@api_view(["POST"])
@permission_classes([IsAuthenticated])
def view_filters_create(request: Request, view_id: int) -> Response:
    """Add a filter to a view configuration."""
    c = _ctx(request)
    f = services.create_view_filter(
        tenant_id=c["tenant_id"],
        organization_node_id=c["organization_node_id"],
        created_by_id=c["user_id"],
        view_id=view_id,
        name=request.data["name"],
        filter_config=request.data.get("filter_config"),
    )
    return Response(
        {
            "id": f.pk,
            "public_id": str(f.public_id),
            "name": f.name,
            "filter_config": f.filter_config,
        },
        status=status.HTTP_201_CREATED,
    )


@api_view(["DELETE"])
@permission_classes([IsAuthenticated])
def view_filters_delete(request: Request, filter_id: int) -> Response:
    """Remove a filter from a view."""
    services.delete_view_filter(filter_id=filter_id)
    return Response(status=status.HTTP_204_NO_CONTENT)


# ═════════════════════════════════════════════════════════════════════════════
# View Groupings (for board/kanban)
# ═════════════════════════════════════════════════════════════════════════════

@api_view(["PUT"])
@permission_classes([IsAuthenticated])
def view_groupings_update(request: Request, view_id: int) -> Response:
    """Replace groupings for a view."""
    groupings = services.update_view_groupings(
        view_id=view_id,
        groupings=request.data.get("groupings", []),
    )
    return Response(
        {
            "groupings": [
                {"id": g.pk, "field_name": g.field_name, "label_key": g.label_key, "color": g.color}
                for g in groupings
            ]
        },
    )


# ═════════════════════════════════════════════════════════════════════════════
# Dashboard CRUD
# ═════════════════════════════════════════════════════════════════════════════

@api_view(["GET"])
@permission_classes([IsAuthenticated])
def dashboards_list(request: Request) -> Response:
    """List dashboards for the current tenant."""
    c = _ctx(request)
    qs = selectors.get_dashboards(tenant_id=c["tenant_id"])
    data = [
        {
            "id": d.pk,
            "public_id": str(d.public_id),
            "name": d.name,
            "label_key": d.label_key,
            "icon": d.icon,
            "is_default": d.is_default,
            "visibility": d.visibility,
            "config": d.config,
            "widgets": [
                {
                    "id": w.pk,
                    "widget_type": w.widget_type,
                    "title_key": w.title_key,
                    "row_index": w.row_index,
                    "col_span": w.col_span,
                    "sort_order": w.sort_order,
                    "config": w.config,
                }
                for w in d.widgets.all()
            ],
        }
        for d in qs
    ]
    return Response(data)


@api_view(["POST"])
@permission_classes([IsAuthenticated])
def dashboards_create(request: Request) -> Response:
    """Create a new dashboard."""
    c = _ctx(request)
    dashboard = services.create_dashboard(
        tenant_id=c["tenant_id"],
        organization_node_id=c["organization_node_id"],
        created_by_id=c["user_id"],
        name=request.data["name"],
        label_key=request.data.get("label_key", ""),
        icon=request.data.get("icon", "grid"),
        visibility=request.data.get("visibility", "private"),
        config=request.data.get("config"),
    )
    return Response(
        {
            "id": dashboard.pk,
            "public_id": str(dashboard.public_id),
            "name": dashboard.name,
            "label_key": dashboard.label_key,
            "icon": dashboard.icon,
            "visibility": dashboard.visibility,
        },
        status=status.HTTP_201_CREATED,
    )


@api_view(["GET"])
@permission_classes([IsAuthenticated])
def dashboards_detail(request: Request, dashboard_id: int) -> Response:
    """Get a single dashboard with its widgets."""
    c = _ctx(request)
    dashboard = selectors.get_dashboard(tenant_id=c["tenant_id"], dashboard_id=dashboard_id)
    return Response(
        {
            "id": dashboard.pk,
            "public_id": str(dashboard.public_id),
            "name": dashboard.name,
            "label_key": dashboard.label_key,
            "icon": dashboard.icon,
            "is_default": dashboard.is_default,
            "is_system": dashboard.is_system,
            "visibility": dashboard.visibility,
            "config": dashboard.config,
            "sort_order": dashboard.sort_order,
            "created_at": dashboard.created_at.isoformat() if dashboard.created_at else None,
            "updated_at": dashboard.updated_at.isoformat() if dashboard.updated_at else None,
            "widgets": [
                {
                    "id": w.pk,
                    "widget_type": w.widget_type,
                    "title_key": w.title_key,
                    "row_index": w.row_index,
                    "col_span": w.col_span,
                    "sort_order": w.sort_order,
                    "config": w.config,
                }
                for w in dashboard.widgets.all()
            ],
        },
    )


@api_view(["PUT", "PATCH"])
@permission_classes([IsAuthenticated])
def dashboards_update(request: Request, dashboard_id: int) -> Response:
    """Update a dashboard."""
    c = _ctx(request)
    dashboard = services.update_dashboard(
        dashboard_id=dashboard_id,
        updated_by_id=c["user_id"],
        name=request.data.get("name"),
        label_key=request.data.get("label_key"),
        icon=request.data.get("icon"),
        visibility=request.data.get("visibility"),
        config=request.data.get("config"),
    )
    if "widgets" in request.data:
        services.update_dashboard_widgets(
            dashboard_id=dashboard_id,
            widgets_data=request.data["widgets"],
        )
    return Response(
        {
            "id": dashboard.pk,
            "name": dashboard.name,
            "label_key": dashboard.label_key,
            "icon": dashboard.icon,
            "visibility": dashboard.visibility,
            "updated_at": dashboard.updated_at.isoformat(),
        },
    )


@api_view(["DELETE"])
@permission_classes([IsAuthenticated])
def dashboards_delete(request: Request, dashboard_id: int) -> Response:
    """Delete a dashboard."""
    services.delete_dashboard(dashboard_id=dashboard_id)
    return Response(status=status.HTTP_204_NO_CONTENT)


# ═════════════════════════════════════════════════════════════════════════════
# Dashboard Widgets
# ═════════════════════════════════════════════════════════════════════════════

@api_view(["POST"])
@permission_classes([IsAuthenticated])
def dashboard_widgets_create(request: Request, dashboard_id: int) -> Response:
    """Add a widget to a dashboard."""
    c = _ctx(request)
    w = services.create_dashboard_widget(
        tenant_id=c["tenant_id"],
        organization_node_id=c["organization_node_id"],
        dashboard_id=dashboard_id,
        widget_type=request.data["widget_type"],
        title_key=request.data.get("title_key", ""),
        row_index=request.data.get("row_index", 0),
        col_span=request.data.get("col_span", 3),
        sort_order=request.data.get("sort_order", 0),
        config=request.data.get("config"),
    )
    return Response(
        {
            "id": w.pk,
            "widget_type": w.widget_type,
            "title_key": w.title_key,
            "row_index": w.row_index,
            "col_span": w.col_span,
            "sort_order": w.sort_order,
            "config": w.config,
        },
        status=status.HTTP_201_CREATED,
    )


# ═════════════════════════════════════════════════════════════════════════════
# Chart Configuration CRUD
# ═════════════════════════════════════════════════════════════════════════════

@api_view(["GET"])
@permission_classes([IsAuthenticated])
def chart_configurations_list(request: Request) -> Response:
    """List chart configurations."""
    c = _ctx(request)
    entity = request.query_params.get("entity")
    qs = selectors.get_chart_configurations(
        tenant_id=c["tenant_id"],
        entity_name=entity,
    )
    data = [
        {
            "id": ch.pk,
            "public_id": str(ch.public_id),
            "name": ch.name,
            "entity_name": ch.entity_name,
            "chart_type": ch.chart_type,
            "config": ch.config,
            "is_default": ch.is_default,
            "visibility": ch.visibility,
            "created_at": ch.created_at.isoformat() if ch.created_at else None,
            "updated_at": ch.updated_at.isoformat() if ch.updated_at else None,
        }
        for ch in qs
    ]
    return Response(data)


@api_view(["POST"])
@permission_classes([IsAuthenticated])
def chart_configurations_create(request: Request) -> Response:
    """Create a chart configuration."""
    c = _ctx(request)
    chart = services.create_chart_configuration(
        tenant_id=c["tenant_id"],
        organization_node_id=c["organization_node_id"],
        created_by_id=c["user_id"],
        entity_name=request.data["entity_name"],
        chart_type=request.data["chart_type"],
        name=request.data["name"],
        config=request.data.get("config"),
        visibility=request.data.get("visibility", "private"),
    )
    return Response(
        {
            "id": chart.pk,
            "public_id": str(chart.public_id),
            "name": chart.name,
            "entity_name": chart.entity_name,
            "chart_type": chart.chart_type,
            "config": chart.config,
            "is_default": chart.is_default,
            "visibility": chart.visibility,
            "created_at": chart.created_at.isoformat(),
        },
        status=status.HTTP_201_CREATED,
    )


@api_view(["GET"])
@permission_classes([IsAuthenticated])
def chart_configurations_detail(request: Request, chart_id: int) -> Response:
    """Get a single chart configuration."""
    c = _ctx(request)
    chart = selectors.get_chart_configuration(tenant_id=c["tenant_id"], chart_id=chart_id)
    return Response(
        {
            "id": chart.pk,
            "public_id": str(chart.public_id),
            "name": chart.name,
            "entity_name": chart.entity_name,
            "chart_type": chart.chart_type,
            "config": chart.config,
            "is_default": chart.is_default,
            "visibility": chart.visibility,
            "created_at": chart.created_at.isoformat() if chart.created_at else None,
            "updated_at": chart.updated_at.isoformat() if chart.updated_at else None,
        },
    )


@api_view(["PUT", "PATCH"])
@permission_classes([IsAuthenticated])
def chart_configurations_update(request: Request, chart_id: int) -> Response:
    """Update a chart configuration."""
    c = _ctx(request)
    chart = services.update_chart_configuration(
        chart_id=chart_id,
        updated_by_id=c["user_id"],
        name=request.data.get("name"),
        config=request.data.get("config"),
        visibility=request.data.get("visibility"),
    )
    return Response(
        {
            "id": chart.pk,
            "name": chart.name,
            "entity_name": chart.entity_name,
            "chart_type": chart.chart_type,
            "config": chart.config,
            "visibility": chart.visibility,
            "updated_at": chart.updated_at.isoformat(),
        },
    )


@api_view(["DELETE"])
@permission_classes([IsAuthenticated])
def chart_configurations_delete(request: Request, chart_id: int) -> Response:
    """Delete a chart configuration."""
    services.delete_chart_configuration(chart_id=chart_id)
    return Response(status=status.HTTP_204_NO_CONTENT)
