from __future__ import annotations

from enum import Enum
from itertools import chain
from typing import Set


class ValidSqlTokens(str, Enum):
    SELECT = "SELECT"
    ASTERISK = "*"
    DISTINCT = "DISTINCT"
    INTO = "INTO"
    TOP = "TOP"
    AS = "AS"
    FROM = "FROM"
    WHERE = "WHERE"
    AND = "AND"
    OR = "OR"
    BETWEEN = "BETWEEN"
    LIKE = "LIKE"
    IN = "IN"
    IS = "IS"
    NULL = "NULL"
    NOT = "NOT"
    CREATE = "CREATE"
    DATABASE = "DATABASE"
    TABLE = "TABLE"
    INDEX = "INDEX"
    VIEW = "VIEW"
    DROP = "DROP"
    UPDATE = "UPDATE"
    DELETE = "DELETE"
    ALTER = "ALTER"
    COLUMN = "COLUMN"
    COUNT = "COUNT"
    SUM = "SUM"
    AVG = "AVG"
    MIN = "MIN"
    MAX = "MAX"
    GROUP = "GROUP"
    BY = "BY"
    HAVING = "HAVING"
    ORDER = "ORDER"
    DESC = "DESC"
    OFFSET = "OFFSET"
    FETCH = "FETCH"
    JOIN = "JOIN"
    INNER = "INNER"
    LEFT = "LEFT"
    RIGHT = "RIGHT"
    FULL = "FULL"
    EXISTS = "EXISTS"
    GRANT = "GRANT"
    REVOKE = "REVOKE"
    SAVEPOINT = "SAVEPOINT"
    COMMIT = "COMMIT"
    ROLLBACK = "ROLLBACK"
    TRUNCATE = "TRUNCATE"
    UNION = "UNION"
    ALL = "ALL"
    CAST = "CAST"


class ValidSqlAlchemyTypes(str, Enum):
    ARRAY = "ARRAY"
    BIGINT = "BIGINT"
    BINARY = "BINARY"
    BLOB = "BLOB"
    BOOLEAN = "BOOLEAN"
    BOOLEANTYPE = "BOOLEANTYPE"
    CHAR = "CHAR"
    CLOB = "CLOB"
    DATE = "DATE"
    DATETIME = "DATETIME"
    DATETIME_TIMEZONE = "DATETIME_TIMEZONE"
    DECIMAL = "DECIMAL"
    FLOAT = "FLOAT"
    INT = "INT"
    INTEGER = "INTEGER"
    INTEGERTYPE = "INTEGERTYPE"
    JSON = "JSON"
    MATCHTYPE = "MATCHTYPE"
    NCHAR = "NCHAR"
    NO_ARG = "NO_ARG"
    NULLTYPE = "NULLTYPE"
    NUMERIC = "NUMERIC"
    NVARCHAR = "NVARCHAR"
    REAL = "REAL"
    SMALLINT = "SMALLINT"
    STRINGTYPE = "STRINGTYPE"
    TABLEVALUE = "TABLEVALUE"
    TEXT = "TEXT"
    TIMESTAMP = "TIMESTAMP"
    TIME_TIMEZONE = "TIME_TIMEZONE"
    VARBINARY = "VARBINARY"
    VARCHAR = "VARCHAR"


class ValidSparkSqlTypes(str, Enum):
    ARRAYTYPE = "ARRAY"
    BINARYTYPE = "BINARY"
    BOOLEAN = "BOOLEAN"
    BYTE = "BYTE"
    TINYINT = "TINYINT"
    DATE = "DATE"
    DECIMAL = "DECIMAL"
    DEC = "DEC"
    NUMERIC = "NUMERIC"
    INTERVAL = "INTERVAL"
    DAY = "DAY"
    YEAR = "YEAR"
    MONTH = "MONTH"
    HOUR = "HOUR"
    SECOND = "SECOND"
    MINUTE = "MINUTE"
    DOUBLE = "DOUBLE"
    FLOAT = "FLOAT"
    REAL = "REAL"
    INTEGER = "INTEGER"
    INT = "INT"
    LONG = "LONG"
    BIGINT = "BIGINT"
    MAP = "MAP"
    SHORT = "SHORT"
    SMALLINT = "SMALLINT"
    STRING = "STRING"
    STRUCT = "STRUCT"
    TIMESTAMP = "TIMESTAMP"


class ValidSparkSqlTokens(str, Enum):
    SELECT = "SELECT"
    CLUSTER = "CLUSTER"
    ALTER = "ALTER"
    DATABASE = "DATABASE"
    TABLE = "TABLE"
    VIEW = "VIEW"
    FUNCTION = "FUNCTION"
    DROP = "DROP"
    REPAIR = "REPAIR"
    TRUNCATE = "TRUNCATE"
    USE = "USE"
    INSERT = "INSERT"
    LOAD = "LOAD"
    OVERWRITE = "OVERWRITE"
    DIRECTORY = "DIRECTORY"
    BY = "BY"
    DISTRIBUTE = "DISTRIBUTE"
    HAVING = "HAVING"
    GROUP = "GROUP"
    JOIN = "JOIN"
    LIKE = "LIKE"
    ORDER = "ORDER"
    SORT = "SORT"
    TABLESAMPLE = "TABLESAMPLE"
    WHERE = "WHERE"
    CASE = "CASE"
    PIVOT = "PIVOT"
    LATERAL = "LATERAL"
    TRANSFORM = "TRANSFORM"
    EXPLAIN = "EXPLAIN"
    ADD = "ADD"
    FILE = "FILE"
    JAR = "JAR"
    CACHE = "CACHE"
    CLEAR = "CLEAR"
    ANALYZE = "ANALYZE"
    DESCRIBE = "DESCRIBE"
    QUERY = "QUERY"
    LIST = "LIST"
    REFRESH = "REFRESH"
    RESET = "RESET"
    SET = "SET"
    SHOW = "SHOW"
    COLUMNS = "COLUMNS"
    DATABASES = "DATABASES"
    FUNCTIONS = "FUNCTIONS"
    PARTITIONS = "PARTITIONS"
    EXTENDED = "EXTENDED"
    TABLES = "TABLES"
    TBLPROPERTIES = "TBLPROPERTIES"
    VIEWS = "VIEWS"
    UNCACHE = "UNCACHE"
    EXCEPT = "EXCEPT"
    MINUS = "MINUS"
    INTERSECT = "INTERSECT"
    UNION = "UNION"
    ALL = "ALL"
    FROM = "FROM"
    DISTINCT = "DISTINCT"
    WITH = "WITH"
    AS = "AS"
    MAX = "MAX"
    VALUES = "VALUES"
    GROUPING = "GROUPING"
    SETS = "SETS"
    ROLLUP = "ROLLUP"
    CUBE = "CUBE"
    MIN = "MIN"
    COUNT = "COUNT"
    SUM = "SUM"
    AVG = "AVG"
    FILTER = "FILTER"
    FIRST = "FIRST"
    IGNORE = "IGNORE"
    LAST = "LAST"
    NATURAL = "NATURAL"
    INNER = "INNER"
    CROSS = "CROSS"
    LEFT = "LEFT"
    OUTER = "OUTER"
    SEMI = "SEMI"
    RIGHT = "RIGHT"
    FULL = "FULL"
    ANTI = "ANTI"
    ON = "ON"
    USING = "USING"
    NOT = "NOT"
    ESCAPE = "ESCAPE"
    LIMIT = "LIMIT"
    LENGTH = "LENGTH"
    ASTERISK = "*"
    ASC = "ASC"
    DESC = "DESC"
    NULLS = "NULLS"
    ROWS = "ROWS"
    OUT = "OUT"
    OF = "OF"
    RANGE = "RANGE"
    EXPLODE = "EXPLODE"
    EXPLODE_OUTER = "EXPLODE_OUTER"
    INLINE = "INLINE"
    INLINE_OUTER = "INLINE_OUTER"
    POSEXPLODE = "POSEXPLODE"
    POSEXPLODE_OUTER = "POSEXPLODE_OUTER"
    STACK = "STACK"
    JSON_TUPE = "JSON_TUPE"
    PARSE_URL = "PARSE_URL"
    RANK = "RANK"
    DENSE_RANK = "DENSE_RANK"
    PERCENT_RANK = "PERCENT_RANK"
    NTILE = "NTILE"
    ROW_NUMBER = "ROW_NUMBER"
    RESPECT = "RESPECT"
    CUME_DIST = "CUME_DIST"
    LAG = "LAG"
    LEAD = "LEAD"
    NTH_VALUE = "NTH_VALUE"
    FIRST_VALUE = "FIRST_VALUE"
    LAST_VALUE = "LAST_VALUE"
    PRECEDING = "PRECEDING"
    BETWEEN = "BETWEEN"
    AND = "AND"
    CURRENT = "CURRENT"
    FOLLOWING = "FOLLOWING"
    UNBOUNDED = "UNBOUNDED"
    WHEN = "WHEN"
    THEN = "THEN"
    ELSE = "ELSE"
    FOR = "FOR"


valid_sql_tokens_and_types: Set[str] = set(
    chain.from_iterable(
        [
            list(map(lambda i: i.upper(), ValidSqlTokens.__members__.keys())),
            list(map(lambda i: i.upper(), ValidSqlAlchemyTypes.__members__.keys())),
            list(map(lambda i: i.upper(), ValidSparkSqlTokens.__members__.keys())),
            list(map(lambda i: i.upper(), ValidSparkSqlTypes.__members__.keys())),
        ]
    )
)
