open StdLabels
module Path = ImportDataTypes.Path
module Expression = ImportExpression.T

type t = {
  filters : Path.t Expression.t list;
  group : Path.t Expression.t option;
}

(** Ensure the group criteria in window functions match the global group by
    criteria.

    Traverse the configuration tree until finding a group window. *)

(** Check if the expression contains a group function *)
let matchWindowGroup : 'a ImportExpression.T.t -> bool =
 fun expression ->
  let exception Found in
  let open ImportExpression.T in
  let rec f = function
    | Empty | Literal _ | Integer _ | Path _ -> ()
    | Expr e -> f e
    | Concat pp | Function' (_, pp) | Function (_, pp) | Nvl pp | Join (_, pp)
      -> List.iter ~f pp
    | Window (_, _, _) -> raise Found
    | BOperator (_, arg1, arg2) ->
        f arg1;
        f arg2
    | GEquality (_, arg1, args) ->
        f arg1;
        List.iter ~f args
  in
  try
    f expression;
    false
  with
  | Found -> true

(** Transform a list of expression into a list of CTE to evaluate. *)
let of_filters : Path.t Expression.t list -> t list =
 fun filters ->
  let last_group, prev =
    List.fold_left filters
      ~init:({ filters = []; group = None }, [])
      ~f:(fun (cte, acc) expr ->
        begin
          if matchWindowGroup expr then
            ( { filters = []; group = None },
              { cte with group = Some expr } :: acc )
          else ({ cte with filters = expr :: cte.filters }, acc)
        end)
  in
  List.rev (last_group :: prev)