from dataclasses import dataclass, field
from typing import List, Union, Optional, Any, Set

@dataclass
class QueryState:
    """
    Holds the semantic state of a query (AST-lite).
    This allows us to build the query in any order and compile it
    deterministically later.
    """
    # CTEs (Common Table Expressions) — list of (alias, query, recursive) tuples
    ctes: List[Any] = field(default_factory=list)
    
    # Window definitions (named windows)
    window_definitions: dict = field(default_factory=dict)  # {name: WindowSpec}
    
    # Chained statements (previous QueryStates in a chain)
    chain: List['QueryState'] = field(default_factory=list)

    # SELECT
    selects: List[Union[str, Any]] = field(default_factory=list)
    distinct: bool = False
    
    # FROM
    from_sources: List[Union[str, Any]] = field(default_factory=list)
    
    # JOIN — each entry is a tuple (join_sql, on_condition_or_None)
    joins: List[Any] = field(default_factory=list)
    
    # WHERE
    wheres: List[Union[str, Any]] = field(default_factory=list)
    
    # GROUP BY
    groups: List[Union[str, Any]] = field(default_factory=list)

    # HAVING
    havings: List[Union[str, Any]] = field(default_factory=list)

    # ORDER BY
    orders: List[str] = field(default_factory=list)
    
    # LIMIT / OFFSET
    limit: Optional[int] = None
    offset: Optional[int] = None

    # INSERT / UPDATE / DELETE
    # We might need to track the "type" of query if it's not a SELECT
    # For now, let's focus on SELECT/DQL, but keep space for DML
    statement_type: str = 'SELECT'
    
    # DML specific
    insert_table: Optional[str] = None
    insert_columns: List[str] = field(default_factory=list)
    update_table: Optional[str] = None
    delete_table: Optional[str] = None
    
    values: List[str] = field(default_factory=list)
    insert_values: List[tuple] = field(default_factory=list)
    updates: List[str] = field(default_factory=list)
    
    # RETURNING
    returning: List[str] = field(default_factory=list)

    # ON CONFLICT
    on_conflict_target: List[str] = field(default_factory=list)
    on_conflict_action: Optional[str] = None  # DO NOTHING or DO UPDATE
    on_conflict_updates: List[Any] = field(default_factory=list)
    on_conflict_where: List[Any] = field(default_factory=list)

    # Set operations: UNION, UNION ALL, INTERSECT, EXCEPT
    # Each entry is (operator_str, QueryState)
    union_queries: List[Any] = field(default_factory=list)

    # Metadata
    aliases: dict = field(default_factory=dict)
