"""
Test route registry functionality
"""

import pytest

from src.local_deep_research.web.routes.route_registry import (
    ROUTE_REGISTRY,
    find_route,
    get_all_routes,
    get_routes_by_blueprint,
)


class TestRouteRegistry:
    """Test the route registry module"""

    def test_route_registry_structure(self):
        """Test that ROUTE_REGISTRY has the expected structure"""
        # Check that we have the expected blueprints
        expected_blueprints = [
            "research",
            "api_v1",
            "history",
            "settings",
            "metrics",
        ]
        assert set(ROUTE_REGISTRY.keys()) == set(expected_blueprints)

        # Check each blueprint has required keys
        for blueprint_name, blueprint_info in ROUTE_REGISTRY.items():
            assert "blueprint" in blueprint_info
            assert "url_prefix" in blueprint_info
            assert "routes" in blueprint_info
            assert isinstance(blueprint_info["routes"], list)

            # Check each route has the expected format
            for route in blueprint_info["routes"]:
                assert len(route) == 4  # (method, path, endpoint, description)
                method, path, endpoint, description = route
                assert isinstance(method, str)
                assert method in ["GET", "POST", "DELETE", "PUT", "PATCH"]
                assert isinstance(path, str)
                assert isinstance(endpoint, str)
                assert isinstance(description, str)

    def test_get_all_routes(self):
        """Test get_all_routes function"""
        all_routes = get_all_routes()

        # Should return a list
        assert isinstance(all_routes, list)
        assert len(all_routes) > 0

        # Check structure of returned routes
        for route in all_routes:
            assert isinstance(route, dict)
            assert "method" in route
            assert "path" in route
            assert "endpoint" in route
            assert "description" in route
            assert "blueprint" in route

        # Check that paths are properly prefixed
        api_v1_routes = [r for r in all_routes if r["blueprint"] == "api_v1"]
        for route in api_v1_routes:
            assert route["path"].startswith("/api/v1")

        # Check that research routes are at root level
        research_routes = [
            r for r in all_routes if r["blueprint"] == "research"
        ]
        root_route = next(
            (r for r in research_routes if r["endpoint"] == "research.index"),
            None,
        )
        assert root_route is not None
        assert root_route["path"] == "/"

    def test_get_routes_by_blueprint(self):
        """Test get_routes_by_blueprint function"""
        # Test valid blueprint
        settings_routes = get_routes_by_blueprint("settings")
        assert isinstance(settings_routes, list)
        assert len(settings_routes) > 0

        # All routes should be from settings blueprint
        for route in settings_routes:
            assert route["path"].startswith("/settings")

        # Test invalid blueprint
        invalid_routes = get_routes_by_blueprint("invalid_blueprint")
        assert invalid_routes == []

        # Test specific routes
        settings_page = next(
            (r for r in settings_routes if r["endpoint"] == "settings_page"),
            None,
        )
        assert settings_page is not None
        assert settings_page["path"] == "/settings/"
        assert settings_page["method"] == "GET"

    def test_find_route(self):
        """Test find_route function"""
        # Test finding routes by pattern
        api_routes = find_route("/api")
        assert len(api_routes) > 0
        for route in api_routes:
            assert "/api" in route["path"].lower()

        # Test finding specific route
        history_routes = find_route("history")
        assert len(history_routes) > 0

        # Test case insensitive search
        metrics_routes = find_route("METRICS")
        assert len(metrics_routes) > 0

        # Test pattern not found
        not_found = find_route("nonexistent_pattern")
        assert not_found == []

    def test_route_uniqueness(self):
        """Test that route paths are unique within their method"""
        all_routes = get_all_routes()

        # Group by method and path
        route_map = {}
        for route in all_routes:
            key = (route["method"], route["path"])
            if key in route_map:
                # Found duplicate
                pytest.fail(
                    f"Duplicate route found: {route['method']} {route['path']} "
                    f"in {route['blueprint']} and {route_map[key]['blueprint']}"
                )
            route_map[key] = route

    def test_api_routes_consistency(self):
        """Test that API routes follow consistent patterns"""
        all_routes = get_all_routes()
        api_routes = [r for r in all_routes if "/api" in r["path"]]

        for route in api_routes:
            # API routes should use proper REST methods
            if "get" in route["endpoint"] or "status" in route["endpoint"]:
                assert route["method"] == "GET", (
                    f"GET method expected for {route['endpoint']}"
                )
            elif (
                "create" in route["endpoint"]
                or "save" in route["endpoint"]
                or "update" in route["endpoint"]
            ):
                assert route["method"] in ["POST", "PUT", "PATCH"], (
                    f"POST/PUT/PATCH expected for {route['endpoint']}"
                )
            elif "delete" in route["endpoint"] or "clear" in route["endpoint"]:
                assert route["method"] in ["DELETE", "POST"], (
                    f"DELETE/POST expected for {route['endpoint']}"
                )

    def test_research_id_routes(self):
        """Test that routes with research_id parameter are consistent"""
        all_routes = get_all_routes()
        research_id_routes = [
            r
            for r in all_routes
            if "<string:research_id>" in r["path"]
            or "<research_id>" in r["path"]
        ]

        assert len(research_id_routes) > 0, (
            "Should have routes with research_id parameter"
        )

        # Check that research_id routes exist in multiple blueprints
        blueprints_with_research_id = set(
            r["blueprint"] for r in research_id_routes
        )
        assert len(blueprints_with_research_id) >= 3, (
            "Multiple blueprints should have research_id routes"
        )

    def test_settings_api_routes(self):
        """Test settings API routes specifically"""
        settings_routes = get_routes_by_blueprint("settings")

        # Check for CRUD operations on settings
        api_routes = [r for r in settings_routes if "/api" in r["path"]]

        # Should have routes for all CRUD operations
        methods = set(r["method"] for r in api_routes)
        assert "GET" in methods
        assert "POST" in methods
        assert "DELETE" in methods

        # Check for specific important routes
        route_endpoints = [r["endpoint"] for r in api_routes]
        assert "api_get_all_settings" in route_endpoints
        assert "api_update_setting" in route_endpoints
        assert "api_get_available_models" in route_endpoints

    def test_route_documentation(self):
        """Test that all routes have descriptions"""
        all_routes = get_all_routes()

        for route in all_routes:
            # Every route should have a non-empty description
            assert route["description"], (
                f"Route {route['method']} {route['path']} missing description"
            )
            assert len(route["description"]) > 5, (
                f"Route {route['method']} {route['path']} has too short description"
            )

    def test_blueprint_naming_consistency(self):
        """Test that blueprint names are consistent"""
        for blueprint_name, blueprint_info in ROUTE_REGISTRY.items():
            # Blueprint field should match the key with _bp suffix (except api_v1)
            if blueprint_name == "api_v1":
                assert blueprint_info["blueprint"] == "api_blueprint"
            else:
                assert blueprint_info["blueprint"] == f"{blueprint_name}_bp"

    def test_url_prefix_consistency(self):
        """Test that URL prefixes match blueprint names"""
        for blueprint_name, blueprint_info in ROUTE_REGISTRY.items():
            if blueprint_name == "research":
                # Research blueprint is at root
                assert blueprint_info["url_prefix"] is None
            elif blueprint_name == "api_v1":
                assert blueprint_info["url_prefix"] == "/api/v1"
            else:
                # Other blueprints should have prefix matching their name
                assert blueprint_info["url_prefix"] == f"/{blueprint_name}"

    def test_parameterized_routes(self):
        """Test routes with parameters"""
        all_routes = get_all_routes()

        # Check for consistent parameter naming
        param_routes = [
            r for r in all_routes if "<" in r["path"] and ">" in r["path"]
        ]

        for route in param_routes:
            # Check common parameters
            if "research_id" in route["path"]:
                # Should be typed as string (research IDs are UUIDs)
                assert (
                    "<string:research_id>" in route["path"]
                    or "<research_id>" in route["path"]
                ), f"research_id should be typed as string in {route['path']}"

            if "resource_id" in route["path"]:
                assert "<int:resource_id>" in route["path"], (
                    f"resource_id should be typed as int in {route['path']}"
                )

    def test_special_routes(self):
        """Test special routes like health checks and documentation"""
        all_routes = get_all_routes()

        # Should have a health check endpoint
        health_routes = [r for r in all_routes if "health" in r["endpoint"]]
        assert len(health_routes) > 0, (
            "Should have at least one health check route"
        )

        # Should have documentation routes
        doc_routes = [
            r for r in all_routes if "documentation" in r["description"].lower()
        ]
        assert len(doc_routes) > 0, "Should have documentation routes"

    def test_metrics_routes(self):
        """Test metrics blueprint routes"""
        metrics_routes = get_routes_by_blueprint("metrics")

        # Should have dashboard and API routes
        dashboard_routes = [
            r
            for r in metrics_routes
            if r["method"] == "GET" and "/api" not in r["path"]
        ]
        api_routes = [r for r in metrics_routes if "/api" in r["path"]]

        assert len(dashboard_routes) >= 3, (
            "Should have multiple dashboard routes"
        )
        assert len(api_routes) >= 5, "Should have multiple API routes"

        # Check for essential metrics routes
        route_paths = [r["path"] for r in metrics_routes]
        assert "/metrics/" in route_paths
        assert "/metrics/costs" in route_paths
        assert "/metrics/api/metrics" in route_paths


if __name__ == "__main__":
    # Run a quick verification when executed directly
    print("Running route registry verification...")

    all_routes = get_all_routes()
    print(f"\nTotal routes: {len(all_routes)}")

    by_blueprint = {}
    for route in all_routes:
        bp = route["blueprint"]
        by_blueprint[bp] = by_blueprint.get(bp, 0) + 1

    print("\nRoutes by blueprint:")
    for bp, count in sorted(by_blueprint.items()):
        print(f"  {bp}: {count}")

    print("\nSample routes:")
    for route in all_routes[:5]:
        print(
            f"  {route['method']:6} {route['path']:40} - {route['description']}"
        )
