#[derive(Debug, Clone, Copy)]
pub enum Token {
    ABORT,
    ACTION,
    ADD,
    AFTER,
    ALL,
    ALTER,
    ALWAYS,
    ANALYZE,
    AND,
    ANY,
    AS,
    ASC,
    ATTACH,
    AUTOINCR,
    BEFORE,
    BEGIN,
    BETWEEN,
    BITAND,
    BITNOT,
    BITOR,
    BLOB,
    BY,
    CASCADE,
    CASE,
    CAST,
    CHECK,
    COLLATE,
    COLUMN,
    COMMA,
    COMMIT,
    CONCAT,
    CONCURRENTLY,
    CONFLICT,
    CONSTRAINT,
    CREATE,
    CTIME,
    CURRENT,
    DATA,
    DATABASE,
    DEFAULT,
    DEFERRABLE,
    DEFERRED,
    DELETE,
    DESC,
    DETACH,
    DISTINCT,
    DO,
    DOT,
    DROP,
    EACH,
    ELSE,
    END,
    EOF,
    EQ,
    ESCAPE,
    EXCEPT,
    EXCLUDE,
    EXCLUDED,
    EXCLUSIVE,
    EXISTS,
    EXPLAIN,
    FAIL,
    FILTER,
    FIRST,
    FLOAT,
    FOLLOWING,
    FOR,
    FOREIGN,
    FROM,
    GE,
    GENERATED,
    GROUP,
    GROUPS,
    GT,
    HAVING,
    ID,
    IF,
    IGNORE,
    ILLEGAL,
    IMMEDIATE,
    IN,
    INDEX,
    INDEXED,
    INITIALLY,
    INSERT,
    INSTEAD,
    INTEGER,
    INTERSECT,
    INTO,
    IS,
    ISNOT,
    ISNULL,
    JOIN,
    KEY,
    LAST,
    LE,
    LIKE,
    LIMIT,
    LOCKED,
    LPAREN,
    LSHIFT,
    LT,
    MATCH,
    MATERIALIZED,
    MINUS,
    NE,
    NO,
    NOT,
    NOTHING,
    NOTNULL,
    NOWAIT,
    NULL,
    NULLS,
    OF,
    OFFSET,
    ON,
    OR,
    ORDER,
    OTHERS,
    OVER,
    PARTITION,
    PLAN,
    PLUS,
    PRAGMA,
    PRECEDING,
    PRIMARY,
    PTR,
    QUERY,
    RAISE,
    RANGE,
    RECURSIVE,
    REFRESH,
    REFERENCES,
    REINDEX,
    RELEASE,
    REM,
    RENAME,
    REPLACE,
    RESTRICT,
    RETURNING,
    ROLLBACK,
    ROW,
    ROWS,
    RPAREN,
    RSHIFT,
    SAVEPOINT,
    SELECT,
    SEMI,
    SET,
    SHARE,
    SKIP,
    SLASH,
    STAR,
    STRING,
    TABLE,
    TEMP,
    THEN,
    TIES,
    TO,
    TRANSACTION,
    TRIGGER,
    UNBOUNDED,
    UNION,
    UNIQUE,
    UPDATE,
    USING,
    VACUUM,
    VALUES,
    VARIABLE,
    VIEW,
    VIRTUAL,
    WHEN,
    WHERE,
    WINDOW,
    WITH,
    WITHOUT,
}

impl Token {
    /// Returns true if this token is an operator that needs spaces around it
    #[inline]
    #[must_use]
    pub const fn is_operator(&self) -> bool {
        matches!(
            self,
            Self::EQ
                | Self::NE
                | Self::LT
                | Self::GT
                | Self::LE
                | Self::GE
                | Self::PLUS
                | Self::MINUS
                | Self::STAR
                | Self::SLASH
                | Self::REM
                | Self::CONCAT
                | Self::BITAND
                | Self::BITOR
                | Self::LSHIFT
                | Self::RSHIFT
        )
    }

    /// Returns true if this token is punctuation (no word-like spacing).
    #[inline]
    #[must_use]
    pub const fn is_punctuation(&self) -> bool {
        matches!(
            self,
            Self::LPAREN | Self::RPAREN | Self::COMMA | Self::SEMI | Self::DOT
        )
    }

    #[must_use]
    pub const fn as_str(&self) -> &'static str {
        match Self::as_str_a_to_f(*self) {
            Some(s) => s,
            None => match Self::as_str_g_to_p(*self) {
                Some(s) => s,
                None => Self::as_str_q_to_z(*self),
            },
        }
    }

    const fn as_str_a_to_f(self) -> Option<&'static str> {
        Some(match self {
            Self::ABORT => "ABORT",
            Self::ACTION => "ACTION",
            Self::ADD => "ADD",
            Self::AFTER => "AFTER",
            Self::ALL => "ALL",
            Self::ALTER => "ALTER",
            Self::ALWAYS => "ALWAYS",
            Self::ANALYZE => "ANALYZE",
            Self::AND => "AND",
            Self::ANY => "ANY",
            Self::AS => "AS",
            Self::ASC => "ASC",
            Self::ATTACH => "ATTACH",
            Self::AUTOINCR => "AUTOINCREMENT",
            Self::BEFORE => "BEFORE",
            Self::BEGIN => "BEGIN",
            Self::BETWEEN => "BETWEEN",
            Self::BITAND => "&",
            Self::BITNOT => "~",
            Self::BITOR => "|",
            Self::BLOB => "BLOB",
            Self::BY => "BY",
            Self::CASCADE => "CASCADE",
            Self::CASE => "CASE",
            Self::CAST => "CAST",
            Self::CHECK => "CHECK",
            Self::COLLATE => "COLLATE",
            Self::COLUMN => "COLUMN",
            Self::COMMA => ",",
            Self::COMMIT => "COMMIT",
            Self::CONCAT => "||",
            Self::CONCURRENTLY => "CONCURRENTLY",
            Self::CONFLICT => "CONFLICT",
            Self::CONSTRAINT => "CONSTRAINT",
            Self::CREATE => "CREATE",
            Self::CTIME => "CTIME",
            Self::CURRENT => "CURRENT",
            Self::DATA => "DATA",
            Self::DATABASE => "DATABASE",
            Self::DEFAULT => "DEFAULT",
            Self::DEFERRABLE => "DEFERRABLE",
            Self::DEFERRED => "DEFERRED",
            Self::DELETE => "DELETE",
            Self::DESC => "DESC",
            Self::DETACH => "DETACH",
            Self::DISTINCT => "DISTINCT",
            Self::DO => "DO",
            Self::DOT => ".",
            Self::DROP => "DROP",
            Self::EACH => "EACH",
            Self::ELSE => "ELSE",
            Self::END => "END",
            Self::EOF => "EOF",
            Self::EQ => "=",
            Self::ESCAPE => "ESCAPE",
            Self::EXCEPT => "EXCEPT",
            Self::EXCLUDE => "EXCLUDE",
            Self::EXCLUDED => "EXCLUDED",
            Self::EXCLUSIVE => "EXCLUSIVE",
            Self::EXISTS => "EXISTS",
            Self::EXPLAIN => "EXPLAIN",
            Self::FAIL => "FAIL",
            Self::FILTER => "FILTER",
            Self::FIRST => "FIRST",
            Self::FLOAT => "FLOAT",
            Self::FOLLOWING => "FOLLOWING",
            Self::FOR => "FOR",
            Self::FOREIGN => "FOREIGN",
            Self::FROM => "FROM",
            _ => return None,
        })
    }

    const fn as_str_g_to_p(self) -> Option<&'static str> {
        Some(match self {
            Self::GE => ">=",
            Self::GENERATED => "GENERATED",
            Self::GROUP => "GROUP",
            Self::GROUPS => "GROUPS",
            Self::GT => ">",
            Self::HAVING => "HAVING",
            Self::ID => "ID",
            Self::IF => "IF",
            Self::IGNORE => "IGNORE",
            Self::ILLEGAL => "ILLEGAL",
            Self::IMMEDIATE => "IMMEDIATE",
            Self::IN => "IN",
            Self::INDEX => "INDEX",
            Self::INDEXED => "INDEXED",
            Self::INITIALLY => "INITIALLY",
            Self::INSERT => "INSERT",
            Self::INSTEAD => "INSTEAD",
            Self::INTEGER => "INTEGER",
            Self::INTERSECT => "INTERSECT",
            Self::INTO => "INTO",
            Self::IS => "IS",
            Self::ISNOT => "IS NOT",
            Self::ISNULL => "ISNULL",
            Self::JOIN => "JOIN",
            Self::KEY => "KEY",
            Self::LAST => "LAST",
            Self::LE => "<=",
            Self::LIKE => "LIKE",
            Self::LIMIT => "LIMIT",
            Self::LOCKED => "LOCKED",
            Self::LPAREN => "(",
            Self::LSHIFT => "<<",
            Self::LT => "<",
            Self::MATCH => "MATCH",
            Self::MATERIALIZED => "MATERIALIZED",
            Self::MINUS => "-",
            Self::NE => "<>",
            Self::NO => "NO",
            Self::NOT => "NOT",
            Self::NOTHING => "NOTHING",
            Self::NOTNULL => "NOTNULL",
            Self::NOWAIT => "NOWAIT",
            Self::NULL => "NULL",
            Self::NULLS => "NULLS",
            Self::OF => "OF",
            Self::OFFSET => "OFFSET",
            Self::ON => "ON",
            Self::OR => "OR",
            Self::ORDER => "ORDER",
            Self::OTHERS => "OTHERS",
            Self::OVER => "OVER",
            Self::PARTITION => "PARTITION",
            Self::PLAN => "PLAN",
            Self::PLUS => "+",
            Self::PRAGMA => "PRAGMA",
            Self::PRECEDING => "PRECEDING",
            Self::PRIMARY => "PRIMARY",
            Self::PTR => "PTR",
            _ => return None,
        })
    }

    const fn as_str_q_to_z(self) -> &'static str {
        match self {
            Self::QUERY => "QUERY",
            Self::RAISE => "RAISE",
            Self::RANGE => "RANGE",
            Self::RECURSIVE => "RECURSIVE",
            Self::REFRESH => "REFRESH",
            Self::REFERENCES => "REFERENCES",
            Self::REINDEX => "REINDEX",
            Self::RELEASE => "RELEASE",
            Self::REM => "%",
            Self::RENAME => "RENAME",
            Self::REPLACE => "REPLACE",
            Self::RESTRICT => "RESTRICT",
            Self::RETURNING => "RETURNING",
            Self::ROLLBACK => "ROLLBACK",
            Self::ROW => "ROW",
            Self::ROWS => "ROWS",
            Self::RPAREN => ")",
            Self::RSHIFT => ">>",
            Self::SAVEPOINT => "SAVEPOINT",
            Self::SELECT => "SELECT",
            Self::SEMI => ";",
            Self::SET => "SET",
            Self::SHARE => "SHARE",
            Self::SKIP => "SKIP",
            Self::SLASH => "/",
            Self::STAR => "*",
            Self::STRING => "STRING",
            Self::TABLE => "TABLE",
            Self::TEMP => "TEMP",
            Self::THEN => "THEN",
            Self::TIES => "TIES",
            Self::TO => "TO",
            Self::TRANSACTION => "TRANSACTION",
            Self::TRIGGER => "TRIGGER",
            Self::UNBOUNDED => "UNBOUNDED",
            Self::UNION => "UNION",
            Self::UNIQUE => "UNIQUE",
            Self::UPDATE => "UPDATE",
            Self::USING => "USING",
            Self::VACUUM => "VACUUM",
            Self::VALUES => "VALUES",
            Self::VARIABLE => "VARIABLE",
            Self::VIEW => "VIEW",
            Self::VIRTUAL => "VIRTUAL",
            Self::WHEN => "WHEN",
            Self::WHERE => "WHERE",
            Self::WINDOW => "WINDOW",
            Self::WITH => "WITH",
            Self::WITHOUT => "WITHOUT",
            // All earlier ranges are covered by as_str_a_to_f / as_str_g_to_p.
            _ => unreachable!(),
        }
    }
}

impl core::fmt::Display for Token {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        write!(f, "{}", self.as_str())
    }
}
