from ..metamodel.compiler import Pass
from ..metamodel.typer import Checker, InferTypes

from ..metamodel.rewrite import (
    DNFUnionSplitter, FormatOutputs, HandleAggregationsAndRanks
)
from .rewrite import (
    AlgorithmPass, AnnotateConstraints, CDC, ConstantsToVars, DeduplicateVars,
    ExtractCommon, ExtractKeys, Flatten, FlattenScript,
    FunctionAnnotations, LiftData, PeriodMath, QuantifyVars, Splinter, SplitMultiCheckRequires,
    UnifyDefinitions,
)

def lqp_passes() -> list[Pass]:
    return [
        Checker(),
        SplitMultiCheckRequires(),
        FunctionAnnotations(),
        AnnotateConstraints(),
        LiftData(),  # Lifts Data nodes to top-level GNF predicates (before Splinter for null safety).
        CDC(), # specialize to physical relations before extracting nested and typing
        InferTypes(),

        ## Start restructuring the metamodel to resemble LQP structure.

        ## Handle GNF and outer join semantics
        DNFUnionSplitter(), # Handle unions that require DNF decomposition
        ExtractKeys(), # Create a logical for each valid combinations of keys
        FormatOutputs(),

        ## Move nested tasks to the top level, and ensure the root logical has the expected
        ## structure.
        ExtractCommon(), # Extracts tasks that will become common after Flatten into their own definition
        Flatten(), # Move nested tasks to the top level, and various related things touched along the way
        FlattenScript(), # Additional flattening specific to scripts
        HandleAggregationsAndRanks(), # Handle aggregation and rank dependencies

        ## Post-flattening passes
        # Period Math breaks relational assumptions used by dependency analysis so we place
        # it after work relying on that.
        PeriodMath(),  # Rewrite date period uses.
        Splinter(), # Splits multi-headed rules into multiple rules

        ## Final cleanup passes to match with LQP needs.
        ConstantsToVars(),  # Turns constants in Updates and Outputs into vars.
        DeduplicateVars(),  # Deduplicates vars in Updates and Outputs.
        QuantifyVars(), # Adds missing existentials
        AlgorithmPass(),  # Passes to make sure we are following loopy invariants
        UnifyDefinitions(), # Unify relations with multiple definitions.
    ]
