"""
Graph validation utilities for WalkFrame.

Provides methods to filter walks based on graph-theoretic properties
like simple paths, cycles, and valid walks.
"""

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from ..core.walk import WalkFrame


def only_simple_paths(walkframe: 'WalkFrame') -> 'WalkFrame':
    """Filter to only simple paths (no node visited twice).

    A simple path is a walk where each node appears at most once.
    This is validated by checking that the count of nodes equals
    the count of distinct nodes for each walk.

    Args:
        walkframe: WalkFrame instance to filter.

    Returns:
        WalkFrame: Filtered WalkFrame (method chaining).

    Examples:
        >>> walks = WalkFrame("data/walks/*.parquet", network=network)
        >>> simple = walks.only_simple_paths().compute()
    """
    # Add validation to query state
    # This will be applied as a HAVING clause in the final query
    walkframe._query_state['validations'].append('simple_paths')
    
    # Modify the query to filter simple paths
    # We need to add a subquery that checks the condition
    # Store this as a special filter that will be processed during SQL building
    walkframe._query_state['filters'].append(
        f"walk_id IN (SELECT walk_id FROM {walkframe._view_name} GROUP BY walk_id HAVING COUNT(node_id) = COUNT(DISTINCT node_id))"
    )
    
    return walkframe


def only_cycles(walkframe: 'WalkFrame') -> 'WalkFrame':
    """Filter to only cycles (walks where first node equals last node).

    A cycle is a walk that starts and ends at the same node.

    Args:
        walkframe: WalkFrame instance to filter.

    Returns:
        WalkFrame: Filtered WalkFrame (method chaining).

    Examples:
        >>> walks = WalkFrame("data/walks/*.parquet", network=network)
        >>> cycles = walks.only_cycles().compute()
    """
    # Add cycle validation
    walkframe._query_state['validations'].append('cycles')
    
    # SQL to find cycles: first node equals last node
    # Use FIRST_VALUE and LAST_VALUE window functions
    walkframe._query_state['filters'].append(
        f"walk_id IN (WITH start_end AS (SELECT walk_id, FIRST_VALUE(node_id) OVER (PARTITION BY walk_id ORDER BY sequence_idx ASC) as start_node, LAST_VALUE(node_id) OVER (PARTITION BY walk_id ORDER BY sequence_idx ASC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) as end_node FROM {walkframe._view_name}) SELECT DISTINCT walk_id FROM start_end WHERE start_node = end_node)"
    )
    
    return walkframe


def only_complex_walks(walkframe: 'WalkFrame') -> 'WalkFrame':
    """Filter to only complex walks (walks that revisit at least one node).

    In graph theory, a walk may repeat nodes; a simple path may not.
    This method keeps only walks where at least one node is visited more
    than once (non-simple paths / cycles and revisits).

    Args:
        walkframe: WalkFrame instance to filter.

    Returns:
        WalkFrame: Filtered WalkFrame (method chaining).

    Examples:
        >>> walks = WalkFrame("data/walks/*.parquet", network=network)
        >>> non_simple = walks.only_complex_walks().compute()
    """
    walkframe._query_state['validations'].append('complex_walks')
    
    # Filter walks where count != distinct count (nodes repeated)
    walkframe._query_state['filters'].append(
        f"walk_id IN (SELECT walk_id FROM {walkframe._view_name} GROUP BY walk_id HAVING COUNT(node_id) != COUNT(DISTINCT node_id))"
    )
    
    return walkframe
