"""Every cross-entity id field on a backend model: what entity it points at, and where that
entity is resolved from an id.

OpenSwarm stores entities as JSON records that point at each other with bare strings. A workflow
holds `edit_agent_session_id`, an app record holds `workspace_id`, a dashboard card holds
`session_id`. Nothing at the type level says the referent exists, so a reader that forgets the miss
renders a blank instead of a designed empty state. This module is the one place that says what each
pointer means, and the `dangling-refs` linter check (linter/checks/dangling_refs.py) fails any new
`*_id` / `*_ids` field on a backend model that is not declared here.

Data only, no logic: nothing resolves a pointer for you. The `EntityStore` rows name the function
that does, and the linter checks those names still exist so a rename can't quietly rot this file.
"""

from __future__ import annotations

from enum import Enum
from typing import List

from pydantic import BaseModel, ConfigDict


class EntityKind(str, Enum):
    """A record type other records point at by id."""

    SESSION = "session"
    DASHBOARD = "dashboard"
    WORKFLOW = "workflow"
    WORKFLOW_RUN = "workflow_run"
    OUTPUT = "output"
    WORKSPACE = "workspace"
    CLOUD_WORKFLOW = "cloud_workflow"
    # A provider login in 9router's own db, not one of our JSON records.
    PROVIDER_CONNECTION = "provider_connection"


class EntityStore(BaseModel):
    """Where one entity kind is looked up by id, so a reader knows what a pointer resolves against."""

    model_config = ConfigDict(validate_assignment=True, frozen=True)

    kind: EntityKind
    module: str
    lookup: str


class EntityReference(BaseModel):
    """One id field on one backend model, and the entity kind it points at."""

    model_config = ConfigDict(validate_assignment=True, frozen=True)

    module: str
    model: str
    field: str
    target: EntityKind


ENTITY_STORES: List[EntityStore] = [
    EntityStore(kind=EntityKind.SESSION, module="backend.apps.agents.manager.session.session_store", lookup="load_session_data"),
    EntityStore(kind=EntityKind.DASHBOARD, module="backend.apps.dashboards.dashboards", lookup="load"),
    EntityStore(kind=EntityKind.WORKFLOW, module="backend.apps.workflows.storage", lookup="get_workflow"),
    # No get_run(run_id) exists, so a run is found by scanning the listing; a stale last_run_id just reads as "no run".
    EntityStore(kind=EntityKind.WORKFLOW_RUN, module="backend.apps.workflows.storage", lookup="list_all_runs"),
    EntityStore(kind=EntityKind.OUTPUT, module="backend.apps.outputs.workspace_io", lookup="load_output"),
    # A workspace is a folder on disk, not a record, so its only by-id lookup is the read route.
    EntityStore(kind=EntityKind.WORKSPACE, module="backend.apps.outputs.outputs", lookup="read_workspace"),
    # The one referent that does not live on this machine. preflight asks the cloud whether it still has the row; a miss renders as "nothing is running this", never as a silent blank.
    EntityStore(kind=EntityKind.CLOUD_WORKFLOW, module="backend.apps.workflows.cloud.client", lookup="preflight"),
    EntityStore(kind=EntityKind.PROVIDER_CONNECTION, module="backend.apps.nine_router.credential_store", lookup="read_credential"),
]

CROSS_ENTITY_REFERENCES: List[EntityReference] = [
    EntityReference(module="backend.apps.agents.core.models", model="AgentConfig", field="dashboard_id", target=EntityKind.DASHBOARD),
    EntityReference(module="backend.apps.agents.core.models", model="AgentConfig", field="selected_app_output_ids", target=EntityKind.OUTPUT),
    EntityReference(module="backend.apps.agents.core.models", model="AgentConfig", field="workflow_edit_id", target=EntityKind.WORKFLOW),
    EntityReference(module="backend.apps.agents.core.models", model="AgentConfig", field="workflow_run_id", target=EntityKind.WORKFLOW_RUN),
    EntityReference(module="backend.apps.agents.core.models", model="AgentSession", field="dashboard_id", target=EntityKind.DASHBOARD),
    EntityReference(module="backend.apps.agents.core.models", model="AgentSession", field="parent_session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.agents.core.models", model="AgentSession", field="workflow_edit_id", target=EntityKind.WORKFLOW),
    EntityReference(module="backend.apps.agents.core.models", model="AgentSession", field="workflow_run_id", target=EntityKind.WORKFLOW_RUN),
    EntityReference(module="backend.apps.agents.core.models", model="ApprovalRequest", field="session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.agents.manager.Messaging", model="QueuedMessage", field="selected_app_output_ids", target=EntityKind.OUTPUT),
    EntityReference(module="backend.apps.agents.manager.streaming.HookContext", model="HookContext", field="session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.dashboard_layout.models", model="CardPosition", field="session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.dashboard_layout.models", model="ViewCardPosition", field="output_id", target=EntityKind.OUTPUT),
    EntityReference(module="backend.apps.dashboards.models", model="BrowserCardPosition", field="dashboard_id", target=EntityKind.DASHBOARD),
    EntityReference(module="backend.apps.dashboards.models", model="CardPosition", field="session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.dashboards.models", model="DashboardLayout", field="expanded_session_ids", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.dashboards.models", model="ViewCardPosition", field="output_id", target=EntityKind.OUTPUT),
    EntityReference(module="backend.apps.outputs.models", model="AgentCreateAppRequest", field="parent_session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.outputs.models", model="Output", field="session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.outputs.models", model="Output", field="workspace_id", target=EntityKind.WORKSPACE),
    EntityReference(module="backend.apps.outputs.orphan_workspaces", model="OrphanWorkspace", field="workspace_id", target=EntityKind.WORKSPACE),
    EntityReference(module="backend.apps.outputs.models", model="OutputCreate", field="session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.outputs.models", model="OutputCreate", field="workspace_id", target=EntityKind.WORKSPACE),
    EntityReference(module="backend.apps.outputs.models", model="OutputExecute", field="output_id", target=EntityKind.OUTPUT),
    EntityReference(module="backend.apps.apps_sdk.apps_sdk", model="SpawnAgentRequest", field="dashboard_id", target=EntityKind.DASHBOARD),
    EntityReference(module="backend.apps.apps_sdk.apps_sdk", model="SpawnAgentReply", field="session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.apps_sdk.apps_sdk", model="ToolsListRequest", field="output_id", target=EntityKind.OUTPUT),
    EntityReference(module="backend.apps.apps_sdk.apps_sdk", model="ToolCallRequest", field="output_id", target=EntityKind.OUTPUT),
    EntityReference(module="backend.apps.apps_sdk.tool_grants", model="PendingGrant", field="output_id", target=EntityKind.OUTPUT),
    EntityReference(module="backend.apps.outputs.models", model="OutputExecuteResult", field="output_id", target=EntityKind.OUTPUT),
    EntityReference(module="backend.apps.outputs.models", model="OutputUpdate", field="session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.outputs.models", model="OutputUpdate", field="workspace_id", target=EntityKind.WORKSPACE),
    EntityReference(module="backend.apps.outputs.models", model="PublishPreflightRequest", field="output_id", target=EntityKind.OUTPUT),
    EntityReference(module="backend.apps.outputs.models", model="PublishRequest", field="output_id", target=EntityKind.OUTPUT),
    EntityReference(module="backend.apps.outputs.models", model="WorkspaceSeedRequest", field="workspace_id", target=EntityKind.WORKSPACE),
    EntityReference(module="backend.apps.skills.models", model="SkillWorkspaceSeedRequest", field="workspace_id", target=EntityKind.WORKSPACE),
    EntityReference(module="backend.apps.workflows.models", model="AskRunBody", field="run_id", target=EntityKind.WORKFLOW_RUN),
    EntityReference(module="backend.apps.workflows.models", model="MissedRun", field="workflow_id", target=EntityKind.WORKFLOW),
    EntityReference(module="backend.apps.workflows.models", model="Workflow", field="cloud_workflow_id", target=EntityKind.CLOUD_WORKFLOW),
    EntityReference(module="backend.apps.workflows.cloud.credential_readiness", model="CredentialReadiness", field="connection_ids", target=EntityKind.PROVIDER_CONNECTION),
    EntityReference(module="backend.apps.workflows.models", model="Workflow", field="dashboard_id", target=EntityKind.DASHBOARD),
    EntityReference(module="backend.apps.workflows.models", model="Workflow", field="edit_agent_session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.workflows.models", model="Workflow", field="last_run_id", target=EntityKind.WORKFLOW_RUN),
    EntityReference(module="backend.apps.workflows.models", model="Workflow", field="last_test_session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.workflows.models", model="Workflow", field="schedule_agent_session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.workflows.models", model="Workflow", field="source_session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.workflows.models", model="WorkflowCreate", field="dashboard_id", target=EntityKind.DASHBOARD),
    EntityReference(module="backend.apps.workflows.models", model="WorkflowCreate", field="source_session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.workflows.models", model="WorkflowRun", field="session_id", target=EntityKind.SESSION),
    EntityReference(module="backend.apps.workflows.models", model="WorkflowRun", field="workflow_id", target=EntityKind.WORKFLOW),
]
