"""FilterExpression AST — the abstract syntax tree for authorization filters.

The AST represents conditions that can be pushed to a database query. It is
produced by `authorized_filter()` and consumed by compilers that translate it
to SQLAlchemy filters, Django Q objects, or raw SQL.

Node types:
- AllowAll: No restrictions — the user can access everything.
- DenyAll: No access — the user cannot access anything.
- Compare: A single field comparison (e.g., owner_id == "alice").
- And: All child expressions must be true.
- Or: At least one child expression must be true.
- Not: Negates a child expression (used for DENY policies in deny-override).
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any


class FilterExpression:
    """Base class for all filter AST nodes."""

    pass


@dataclass(frozen=True)
class AllowAll(FilterExpression):
    """No restrictions — user can access all resources of this type."""

    pass


@dataclass(frozen=True)
class DenyAll(FilterExpression):
    """No access — user cannot access any resources of this type."""

    pass


@dataclass(frozen=True)
class Compare(FilterExpression):
    """A single field comparison.

    Represents conditions like `owner_id == "alice"` or `classification in ["SECRET", "TS"]`.

    Attributes:
        field: The resource field name (e.g., "owner_id", "attributes.classification").
            Uses dot-notation stripped of the "resource." prefix.
        op: The comparison operator.
        value: The literal value to compare against.
    """

    field: str
    op: str  # ==, !=, >, <, >=, <=, in, not_in, contains, matches
    value: Any


@dataclass(frozen=True)
class And(FilterExpression):
    """All child expressions must be true (logical AND)."""

    children: list[FilterExpression] = field(default_factory=list)


@dataclass(frozen=True)
class Or(FilterExpression):
    """At least one child expression must be true (logical OR)."""

    children: list[FilterExpression] = field(default_factory=list)


@dataclass(frozen=True)
class Not(FilterExpression):
    """Negates a child expression."""

    child: FilterExpression = field(default_factory=DenyAll)
