"""Console endpoint catalog for OpenAPI spec generation."""

from __future__ import annotations

from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
    from pydantic import BaseModel

from turnstone.api.console_schemas import (
    AssignRoleRequest,
    AuditEventInfo,
    ChannelUserInfo,
    ClusterNodesResponse,
    ClusterOverviewResponse,
    ClusterSnapshotResponse,
    ClusterWorkstreamsResponse,
    ConsoleCreateWsRequest,
    ConsoleCreateWsResponse,
    ConsoleHealthResponse,
    CreateChannelUserRequest,
    CreatePromptTemplateRequest,
    CreateRoleRequest,
    CreateToolPolicyRequest,
    ListAuditEventsResponse,
    ListChannelUsersResponse,
    ListOrgsResponse,
    ListPromptTemplatesResponse,
    ListRolesResponse,
    ListToolPoliciesResponse,
    ListUserRolesResponse,
    NodeDetailResponse,
    OrgInfo,
    PromptTemplateInfo,
    RoleInfo,
    ToolPolicyInfo,
    UpdateOrgRequest,
    UpdatePromptTemplateRequest,
    UpdateRoleRequest,
    UpdateToolPolicyRequest,
    UsageBreakdownItem,
    UsageResponse,
    UserRoleInfo,
)
from turnstone.api.openapi import EndpointSpec, QueryParam, build_openapi
from turnstone.api.schemas import (
    AuthLoginRequest,
    AuthLoginResponse,
    AuthSetupRequest,
    AuthSetupResponse,
    AuthStatusResponse,
    CreateScheduleRequest,
    CreateTokenRequest,
    CreateTokenResponse,
    CreateUserRequest,
    ErrorResponse,
    ListScheduleRunsResponse,
    ListSchedulesResponse,
    ListTokensResponse,
    ListUsersResponse,
    ScheduleInfo,
    StatusResponse,
    UpdateScheduleRequest,
    UserInfo,
)

CONSOLE_ENDPOINTS: list[EndpointSpec] = [
    # --- Cluster ---
    EndpointSpec(
        "/v1/api/cluster/overview",
        "GET",
        "Cluster state summary",
        response_model=ClusterOverviewResponse,
        tags=["Cluster"],
    ),
    EndpointSpec(
        "/v1/api/cluster/nodes",
        "GET",
        "Paginated node list",
        response_model=ClusterNodesResponse,
        query_params=[
            QueryParam(
                "sort", "Sort field", default="activity", enum=["activity", "tokens", "name"]
            ),
            QueryParam("limit", "Page size", schema_type="integer", default=100),
            QueryParam("offset", "Pagination offset", schema_type="integer", default=0),
        ],
        tags=["Cluster"],
    ),
    EndpointSpec(
        "/v1/api/cluster/workstreams",
        "GET",
        "Filtered workstream list",
        response_model=ClusterWorkstreamsResponse,
        query_params=[
            QueryParam(
                "state",
                "Filter by state",
                enum=["running", "thinking", "attention", "idle", "error"],
            ),
            QueryParam("node", "Filter by node_id"),
            QueryParam("search", "Search in name/title/node"),
            QueryParam("sort", "Sort field", default="state", enum=["state", "tokens", "name"]),
            QueryParam("page", "Page number", schema_type="integer", default=1),
            QueryParam("per_page", "Items per page (max 200)", schema_type="integer", default=50),
        ],
        tags=["Cluster"],
    ),
    EndpointSpec(
        "/v1/api/cluster/node/{node_id}",
        "GET",
        "Single node detail",
        response_model=NodeDetailResponse,
        error_codes=[404],
        tags=["Cluster"],
    ),
    EndpointSpec(
        "/v1/api/cluster/workstreams/new",
        "POST",
        "Create workstream via MQ dispatch",
        request_model=ConsoleCreateWsRequest,
        response_model=ConsoleCreateWsResponse,
        error_codes=[400, 404, 503],
        tags=["Cluster"],
    ),
    EndpointSpec(
        "/v1/api/cluster/snapshot",
        "GET",
        "Full cluster state snapshot",
        description="Returns the complete cluster state: all nodes with their workstreams "
        "and overview aggregates. Used for initial load and reconnection.",
        response_model=ClusterSnapshotResponse,
        tags=["Cluster"],
    ),
    # --- Streaming ---
    EndpointSpec(
        "/v1/api/cluster/events",
        "GET",
        "Cluster SSE event stream",
        description="Server-Sent Events stream for real-time cluster updates. "
        "First event is a 'snapshot' with full cluster state, followed by "
        "node_joined, node_lost, cluster_state, ws_created, ws_closed, ws_rename events.",
        tags=["Streaming"],
    ),
    # --- Auth ---
    EndpointSpec(
        "/v1/api/auth/login",
        "POST",
        "Authenticate with a token",
        request_model=AuthLoginRequest,
        response_model=AuthLoginResponse,
        error_codes=[401],
        tags=["Auth"],
    ),
    EndpointSpec(
        "/v1/api/auth/setup",
        "POST",
        "Create first admin user",
        request_model=AuthSetupRequest,
        response_model=AuthSetupResponse,
        error_codes=[400, 409, 503],
        tags=["Auth"],
    ),
    EndpointSpec(
        "/v1/api/auth/status",
        "GET",
        "Return auth state",
        response_model=AuthStatusResponse,
        tags=["Auth"],
    ),
    EndpointSpec(
        "/v1/api/auth/logout",
        "POST",
        "Clear auth cookie",
        response_model=StatusResponse,
        tags=["Auth"],
    ),
    # --- Admin ---
    EndpointSpec(
        "/v1/api/admin/users",
        "GET",
        "List all users",
        response_model=ListUsersResponse,
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/users",
        "POST",
        "Create a user",
        request_model=CreateUserRequest,
        response_model=UserInfo,
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/users/{user_id}",
        "DELETE",
        "Delete a user and their tokens",
        response_model=StatusResponse,
        error_codes=[404],
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/users/{user_id}/tokens",
        "GET",
        "List tokens for a user",
        response_model=ListTokensResponse,
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/users/{user_id}/tokens",
        "POST",
        "Create an API token (raw token shown once)",
        request_model=CreateTokenRequest,
        response_model=CreateTokenResponse,
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/tokens/{token_id}",
        "DELETE",
        "Revoke an API token",
        response_model=StatusResponse,
        error_codes=[404],
        tags=["Admin"],
    ),
    # --- Channels ---
    EndpointSpec(
        "/v1/api/admin/users/{user_id}/channels",
        "GET",
        "List channel links for a user",
        response_model=ListChannelUsersResponse,
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/users/{user_id}/channels",
        "POST",
        "Link a channel account to a user",
        request_model=CreateChannelUserRequest,
        response_model=ChannelUserInfo,
        error_codes=[400, 404, 409],
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/channels/{channel_type}/{channel_user_id}",
        "DELETE",
        "Unlink a channel account",
        response_model=StatusResponse,
        error_codes=[404],
        tags=["Admin"],
    ),
    # --- Schedules ---
    EndpointSpec(
        "/v1/api/admin/schedules",
        "GET",
        "List all scheduled tasks",
        response_model=ListSchedulesResponse,
        tags=["Schedules"],
    ),
    EndpointSpec(
        "/v1/api/admin/schedules",
        "POST",
        "Create a scheduled task",
        request_model=CreateScheduleRequest,
        response_model=ScheduleInfo,
        error_codes=[400],
        tags=["Schedules"],
    ),
    EndpointSpec(
        "/v1/api/admin/schedules/{task_id}",
        "GET",
        "Get a scheduled task",
        response_model=ScheduleInfo,
        error_codes=[404],
        tags=["Schedules"],
    ),
    EndpointSpec(
        "/v1/api/admin/schedules/{task_id}",
        "PUT",
        "Update a scheduled task",
        request_model=UpdateScheduleRequest,
        response_model=ScheduleInfo,
        error_codes=[400, 404],
        tags=["Schedules"],
    ),
    EndpointSpec(
        "/v1/api/admin/schedules/{task_id}",
        "DELETE",
        "Delete a scheduled task",
        response_model=StatusResponse,
        error_codes=[404],
        tags=["Schedules"],
    ),
    EndpointSpec(
        "/v1/api/admin/schedules/{task_id}/runs",
        "GET",
        "List run history for a scheduled task",
        response_model=ListScheduleRunsResponse,
        query_params=[
            QueryParam(
                "limit", "Max results (default 50, max 200)", schema_type="integer", default=50
            ),
        ],
        error_codes=[404],
        tags=["Schedules"],
    ),
    # --- Governance: Roles ---
    EndpointSpec(
        "/v1/api/admin/roles",
        "GET",
        "List all roles",
        response_model=ListRolesResponse,
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/roles",
        "POST",
        "Create a custom role",
        request_model=CreateRoleRequest,
        response_model=RoleInfo,
        error_codes=[400],
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/roles/{role_id}",
        "PUT",
        "Update a role",
        request_model=UpdateRoleRequest,
        response_model=RoleInfo,
        error_codes=[400, 404],
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/roles/{role_id}",
        "DELETE",
        "Delete a custom role",
        response_model=StatusResponse,
        error_codes=[400, 404],
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/users/{user_id}/roles",
        "GET",
        "List roles assigned to a user",
        response_model=ListUserRolesResponse,
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/users/{user_id}/roles",
        "POST",
        "Assign a role to a user",
        request_model=AssignRoleRequest,
        response_model=StatusResponse,
        error_codes=[400, 404],
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/users/{user_id}/roles/{role_id}",
        "DELETE",
        "Unassign a role from a user",
        response_model=StatusResponse,
        error_codes=[404],
        tags=["Admin"],
    ),
    # --- Governance: Orgs ---
    EndpointSpec(
        "/v1/api/admin/orgs",
        "GET",
        "List organizations",
        response_model=ListOrgsResponse,
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/orgs/{org_id}",
        "GET",
        "Get organization details",
        response_model=OrgInfo,
        error_codes=[404],
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/orgs/{org_id}",
        "PUT",
        "Update organization settings",
        request_model=UpdateOrgRequest,
        response_model=OrgInfo,
        error_codes=[404],
        tags=["Admin"],
    ),
    # --- Governance: Tool Policies ---
    EndpointSpec(
        "/v1/api/admin/policies",
        "GET",
        "List tool policies",
        response_model=ListToolPoliciesResponse,
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/policies",
        "POST",
        "Create a tool policy",
        request_model=CreateToolPolicyRequest,
        response_model=ToolPolicyInfo,
        error_codes=[400],
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/policies/{policy_id}",
        "PUT",
        "Update a tool policy",
        request_model=UpdateToolPolicyRequest,
        response_model=ToolPolicyInfo,
        error_codes=[404],
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/policies/{policy_id}",
        "DELETE",
        "Delete a tool policy",
        response_model=StatusResponse,
        error_codes=[404],
        tags=["Admin"],
    ),
    # --- Governance: Prompt Templates ---
    EndpointSpec(
        "/v1/api/admin/templates",
        "GET",
        "List prompt templates",
        response_model=ListPromptTemplatesResponse,
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/templates",
        "POST",
        "Create a prompt template",
        request_model=CreatePromptTemplateRequest,
        response_model=PromptTemplateInfo,
        error_codes=[400],
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/templates/{template_id}",
        "PUT",
        "Update a prompt template",
        request_model=UpdatePromptTemplateRequest,
        response_model=PromptTemplateInfo,
        error_codes=[404],
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/templates/{template_id}",
        "DELETE",
        "Delete a prompt template",
        response_model=StatusResponse,
        error_codes=[404],
        tags=["Admin"],
    ),
    # --- Governance: Usage & Audit ---
    EndpointSpec(
        "/v1/api/admin/usage",
        "GET",
        "Aggregated usage data",
        response_model=UsageResponse,
        query_params=[
            QueryParam("since", "Start timestamp (ISO8601, defaults to last 7 days)"),
            QueryParam("until", "End timestamp (ISO8601)"),
            QueryParam("user_id", "Filter by user"),
            QueryParam("model", "Filter by model"),
            QueryParam(
                "group_by",
                "Group results",
                enum=["day", "hour", "model", "user"],
            ),
        ],
        tags=["Admin"],
    ),
    EndpointSpec(
        "/v1/api/admin/audit",
        "GET",
        "Paginated audit events",
        response_model=ListAuditEventsResponse,
        query_params=[
            QueryParam("action", "Filter by action type"),
            QueryParam("user_id", "Filter by user"),
            QueryParam("since", "Start timestamp (ISO8601)"),
            QueryParam("until", "End timestamp (ISO8601)"),
            QueryParam("limit", "Page size", schema_type="integer", default=50),
            QueryParam("offset", "Pagination offset", schema_type="integer", default=0),
        ],
        tags=["Admin"],
    ),
    # --- Observability ---
    EndpointSpec(
        "/health",
        "GET",
        "Console health check",
        response_model=ConsoleHealthResponse,
        tags=["Observability"],
    ),
]

_ALL_MODELS: list[type[BaseModel]] = [
    ErrorResponse,
    StatusResponse,
    AuthLoginRequest,
    AuthLoginResponse,
    AuthSetupRequest,
    AuthSetupResponse,
    AuthStatusResponse,
    CreateUserRequest,
    UserInfo,
    ListUsersResponse,
    CreateTokenRequest,
    CreateTokenResponse,
    ListTokensResponse,
    ChannelUserInfo,
    CreateChannelUserRequest,
    ListChannelUsersResponse,
    ClusterOverviewResponse,
    ClusterNodesResponse,
    ClusterWorkstreamsResponse,
    NodeDetailResponse,
    ClusterSnapshotResponse,
    ConsoleCreateWsRequest,
    ConsoleCreateWsResponse,
    ConsoleHealthResponse,
    CreateScheduleRequest,
    UpdateScheduleRequest,
    ScheduleInfo,
    ListSchedulesResponse,
    ListScheduleRunsResponse,
    RoleInfo,
    CreateRoleRequest,
    UpdateRoleRequest,
    ListRolesResponse,
    AssignRoleRequest,
    UserRoleInfo,
    ListUserRolesResponse,
    OrgInfo,
    UpdateOrgRequest,
    ListOrgsResponse,
    ToolPolicyInfo,
    CreateToolPolicyRequest,
    UpdateToolPolicyRequest,
    ListToolPoliciesResponse,
    PromptTemplateInfo,
    CreatePromptTemplateRequest,
    UpdatePromptTemplateRequest,
    ListPromptTemplatesResponse,
    UsageBreakdownItem,
    UsageResponse,
    AuditEventInfo,
    ListAuditEventsResponse,
]


def build_console_spec() -> dict[str, Any]:
    """Build the OpenAPI spec for the turnstone console."""
    return build_openapi(
        title="turnstone Console API",
        description="Cluster-wide visibility and control across all turnstone nodes.",
        endpoints=CONSOLE_ENDPOINTS,
        models=_ALL_MODELS,
    )
