import re

from sqlalchemy import ClauseElement, Select
from sqlalchemy.sql.elements import TextClause


def is_read_query(clause: ClauseElement | None) -> bool:
    """
    Determine if a query is a read query.

    This includes SELECT, WITH, SHOW, and DESCRIBE statements.
    It assumes that the clause does not contain semicolon-separated statements like `SELECT 1; TRUNCATE some_table;`,
    but that is not supported by SQLAlchemy in any case.

    This function is used to determine if a query should be routed to a read replica, so we exclude statements that do
    not modify the database but may be used in a write context such as CALL, USE, DO, START TRANSACTION, and COMMIT.
    We also exclude statements that are not expected to be called by an ORM such as EXPLAIN and HELP.
    """
    if isinstance(clause, Select):
        return True
    if not isinstance(clause, TextClause):
        return False
    statement = clause.text.lower()
    # Remove all leading SQL comments (`-- ...` or `/* ... */`) in one pass.
    statement = re.sub(
        r"^(?:\s*(?:--[^\n]*(?:\n|$)|/\*.*?\*/))*\s*",
        "",
        statement,
        flags=re.DOTALL,
    ).strip()
    return statement.startswith(("select", "with", "show", "describe"))
