import logging
from pathlib import Path

from cognite.client import CogniteClient
from cognite.client.data_classes.data_modeling import ViewId
from mcp.server.fastmcp import FastMCP

from cog_mcp.config import Config
from cog_mcp.errors import error_response
from cog_mcp.formatting import (
    format_data_models_overview,
    format_view_schema,
)

logger = logging.getLogger(__name__)

_DOCS_DIR = Path(__file__).parent / "docs"
FILTER_DOCS = (_DOCS_DIR / "filters.md").read_text()
QUERY_DOCS = (_DOCS_DIR / "querying.md").read_text()

EXCLUDED_VIEWS: frozenset[tuple[str, str, str]] = frozenset(
    {
        # Abstract interfaces (only used as `implements` targets)
        ("cdf_cdm", "CogniteDescribable", "v1"),
        ("cdf_cdm", "CogniteSourceable", "v1"),
        ("cdf_cdm", "CogniteSchedulable", "v1"),
        ("cdf_cdm", "CogniteVisualizable", "v1"),
        # 3D-related views
        ("cdf_cdm", "Cognite3DTransformation", "v1"),
        ("cdf_cdm", "Cognite3DObject", "v1"),
        ("cdf_cdm", "Cognite3DModel", "v1"),
        ("cdf_cdm", "Cognite3DRevision", "v1"),
        ("cdf_cdm", "CogniteCADModel", "v1"),
        ("cdf_cdm", "CogniteCADRevision", "v1"),
        ("cdf_cdm", "CogniteCADNode", "v1"),
        ("cdf_cdm", "CognitePointCloudModel", "v1"),
        ("cdf_cdm", "CognitePointCloudRevision", "v1"),
        ("cdf_cdm", "CognitePointCloudVolume", "v1"),
        ("cdf_cdm", "Cognite360ImageModel", "v1"),
        ("cdf_cdm", "Cognite360ImageCollection", "v1"),
        ("cdf_cdm", "Cognite360Image", "v1"),
        ("cdf_cdm", "Cognite360ImageStation", "v1"),
        ("cdf_cdm", "Cognite360ImageAnnotation", "v1"),
        ("cdf_cdm", "CogniteCubeMap", "v1"),
    }
)


def fetch_views(client: CogniteClient, config: Config) -> str:
    """Fetch all configured views and return formatted overview."""
    all_models = []
    for dm_id in config.data_models:
        try:
            result = client.data_modeling.data_models.retrieve(ids=[dm_id], inline_views=True)
            if result:
                all_models.extend(result)
        except Exception as e:
            logger.error("Failed to retrieve data model %s: %s", dm_id, e)

    for model in all_models:
        if hasattr(model, "views") and model.views:
            model.views = [
                v for v in model.views if (v.space, v.external_id, v.version) not in EXCLUDED_VIEWS
            ]

    return format_data_models_overview(all_models)


def fetch_view_schema(client: CogniteClient, space: str, external_id: str, version: str) -> str:
    """Fetch and return formatted schema for a single view."""
    view_id = ViewId(space=space, external_id=external_id, version=version)
    try:
        result = client.data_modeling.views.retrieve(
            ids=[view_id], include_inherited_properties=True
        )
    except Exception as e:
        logger.error("Failed to retrieve view %s/%s/%s: %s", space, external_id, version, e)
        return error_response(f"Failed to retrieve view {space}/{external_id}/{version}: {e}")

    if not result:
        return error_response(f"View {space}/{external_id}/{version} not found")

    return format_view_schema(result[0])


def register_resources(mcp: FastMCP, client: CogniteClient, config: Config) -> None:
    """Register all MCP resources on the FastMCP server."""

    @mcp.resource("cdf://views")
    def list_views() -> str:
        """List all available views with their space, externalId, and version.

        Use these values when calling tools like list_instances or search_instances.
        To get full property schemas, read cdf://views/{space}/{externalId}/{version}.
        """
        return fetch_views(client, config)

    @mcp.resource("cdf://views/{space}/{external_id}/{version}")
    def get_view_schema(space: str, external_id: str, version: str) -> str:
        """Get the full schema of a view including all property names, types, and relations.

        Read this before filtering, sorting, or aggregating to get correct property names.
        Get the space, externalId, and version from cdf://views.
        """
        return fetch_view_schema(client, space, external_id, version)

    @mcp.resource("cdf://docs/filters")
    def filter_docs() -> str:
        """Reference documentation for CDF instance filter syntax.

        Read this resource when you need to construct filter expressions for
        list_instances, search_instances, or aggregate_instances tools.
        """
        return FILTER_DOCS

    @mcp.resource("cdf://docs/querying")
    def query_docs() -> str:
        """Reference documentation for the CDF graph query API.

        Read this resource when you need to construct queries for the
        query_instances tool, including traversals and multi-result-set queries.
        """
        return QUERY_DOCS
