from typing import Dict, List, Union, Tuple
from investigation.utils import get_hashname
import enum


class Operator(enum.Enum):
    eq = "=="
    ne = "!="
    lt = "<"
    le = "<="
    gt = ">"
    ge = ">="
    in_ = "in"
    notin = "~"


def format_statement(k, v, op: Operator):

    bracketed_value, to_locals = bracketing_value(v, allow_nested=True)

    match op:
        case Operator.notin:
            statement = f"~(`{k}` {Operator.in_.value} {bracketed_value})"
        case _:
            statement = f"`{k}` {op.value} {bracketed_value}"
    return statement, to_locals


def format_eq_in_statement(k, v):
    """
    Format an equality or IN statement for a key-value pair.
    """
    if isinstance(v, list):
        return format_statement(k, v, Operator.in_)
    else:
        return format_statement(k, v, Operator.eq)


def bracketing_value(
    value: Union[str, int, float, bool, List],
    allow_nested: bool = False,
    wrap_strings: bool = True,
) -> Tuple[str, Dict[str, List]]:
    to_locals = {}
    if isinstance(value, str):
        value = value.strip("`").strip("'").strip('"')
        if wrap_strings:
            value = f"'{value}'"
        return value, to_locals
    elif isinstance(value, (int, float, bool)):
        return str(value), to_locals
    elif isinstance(value, list):
        if (not allow_nested):
            raise ValueError(f"Nested lists are not supported for bracketing. {value}")
        temp_name = get_hashname()
        new_list = []
        for v in value:
            v_bracketed, _ = bracketing_value(v, allow_nested=False, wrap_strings=False)
            new_list.append(v_bracketed, )
        to_locals[temp_name] = new_list
        return f"@{temp_name}", to_locals
    else:
        raise ValueError(f"Unsupported type for bracketing: {type(value)}")


def format_and_Q_eq_in(query: Dict[str, Union[str, int, float, bool, List]]) -> Tuple[str, Dict[str, List]]:
    """
    Format a query dictionary into a SQL-like WHERE clause.
    """
    statements = []
    to_locals = {}
    for k, v in query.items():
        statement, to_locals_new = format_eq_in_statement(k, v)
        statements.append(statement)
        to_locals.update(to_locals_new)

    return " & ".join(statements), to_locals
