import {
  collectNodesOfType,
  findNodeOfType,
  replaceNodesMatching,
} from "@silverbulletmd/common/tree";
import { lezerToParseTree } from "@silverbulletmd/common/parse_tree";
import { valueNodeToVal } from "./engine";

// @ts-ignore
import { parser } from "./parse-query";

export type Filter = {
  op: string;
  prop: string;
  value: any;
};

export type ParsedQuery = {
  table: string;
  orderBy?: string;
  orderDesc?: boolean;
  limit?: number;
  filter: Filter[];
  select?: string[];
  render?: string;
};

export function parseQuery(query: string): ParsedQuery {
  let n = lezerToParseTree(query, parser.parse(query).topNode);
  // Clean the tree a bit
  replaceNodesMatching(n, (n) => {
    if (!n.type) {
      let trimmed = n.text!.trim();
      if (!trimmed) {
        return null;
      }
      n.text = trimmed;
    }
  });

  // console.log("Parsed", JSON.stringify(n, null, 2));
  let queryNode = n.children![0];
  let parsedQuery: ParsedQuery = {
    table: queryNode.children![0].children![0].text!,
    filter: [],
  };
  let orderByNode = findNodeOfType(queryNode, "OrderClause");
  if (orderByNode) {
    let nameNode = findNodeOfType(orderByNode, "Name");
    parsedQuery.orderBy = nameNode!.children![0].text!;
    let orderNode = findNodeOfType(orderByNode, "Order");
    parsedQuery.orderDesc = orderNode
      ? orderNode.children![0].text! === "desc"
      : false;
  }
  let limitNode = findNodeOfType(queryNode, "LimitClause");
  if (limitNode) {
    let nameNode = findNodeOfType(limitNode, "Number");
    parsedQuery.limit = valueNodeToVal(nameNode!);
  }

  let filterNodes = collectNodesOfType(queryNode, "FilterExpr");
  for (let filterNode of filterNodes) {
    let val: any = undefined;
    let valNode = filterNode.children![2].children![0];
    val = valueNodeToVal(valNode);
    let f: Filter = {
      prop: filterNode.children![0].children![0].text!,
      op: filterNode.children![1].text!,
      value: val,
    };
    parsedQuery.filter.push(f);
  }
  let selectNode = findNodeOfType(queryNode, "SelectClause");
  if (selectNode) {
    // console.log("Select node", JSON.stringify(selectNode));
    parsedQuery.select = [];
    collectNodesOfType(selectNode, "Name").forEach((t) => {
      parsedQuery.select!.push(t.children![0].text!);
    });
    // let nameNode = findNodeOfType(selectNode, "Number");
    // parsedQuery.limit = +nameNode!.children![0].text!;
  }

  let renderNode = findNodeOfType(queryNode, "RenderClause");
  if (renderNode) {
    let renderNameNode = findNodeOfType(renderNode, "PageRef");
    if (!renderNameNode) {
      renderNameNode = findNodeOfType(renderNode, "String");
    }
    parsedQuery.render = valueNodeToVal(renderNameNode!);
  }

  // console.log(JSON.stringify(queryNode, null, 2));
  return parsedQuery;
}
