"""Visitor implementations for expression trees.

This module provides example visitors for converting expressions to various formats
and for analyzing expression trees.
"""

from __future__ import annotations

from typing import Any

from therismos.expr import (
    AllExpr,
    AnyExpr,
    Eq,
    Ge,
    Gt,
    In,
    IsNull,
    Le,
    Lt,
    Ne,
    NotExpr,
    Regex,
)


class StringVisitor:
    """Visitor that converts expressions to string representation."""

    def visit_eq(self, expr: Eq) -> str:
        return f"{expr.field.name} = {expr.value!r}"

    def visit_ne(self, expr: Ne) -> str:
        return f"{expr.field.name} != {expr.value!r}"

    def visit_lt(self, expr: Lt) -> str:
        return f"{expr.field.name} < {expr.value!r}"

    def visit_le(self, expr: Le) -> str:
        return f"{expr.field.name} <= {expr.value!r}"

    def visit_gt(self, expr: Gt) -> str:
        return f"{expr.field.name} > {expr.value!r}"

    def visit_ge(self, expr: Ge) -> str:
        return f"{expr.field.name} >= {expr.value!r}"

    def visit_regex(self, expr: Regex) -> str:
        return f"{expr.field.name} MATCHES {expr.value!r}"

    def visit_in(self, expr: In) -> str:
        values_str = ", ".join(repr(v) for v in expr.values)
        return f"{expr.field.name} IN ({values_str})"

    def visit_is_null(self, expr: IsNull) -> str:
        return f"{expr.field.name} IS {'NULL' if expr.is_null else 'NOT NULL'}"

    def visit_true(self, expr: Any) -> str:
        return "TRUE"

    def visit_false(self, expr: Any) -> str:
        return "FALSE"

    def visit_all(self, expr: AllExpr) -> str:
        parts = [e.accept(self) for e in expr.exprs]
        return "(" + " AND ".join(parts) + ")"

    def visit_any(self, expr: AnyExpr) -> str:
        parts = [e.accept(self) for e in expr.exprs]
        return "(" + " OR ".join(parts) + ")"

    def visit_not(self, expr: NotExpr) -> str:
        return f"NOT({expr.expr.accept(self)})"


class CountVisitor:
    """Visitor that counts the number of nodes in an expression tree."""

    def visit_eq(self, expr: Eq) -> int:
        return 1

    def visit_ne(self, expr: Ne) -> int:
        return 1

    def visit_lt(self, expr: Lt) -> int:
        return 1

    def visit_le(self, expr: Le) -> int:
        return 1

    def visit_gt(self, expr: Gt) -> int:
        return 1

    def visit_ge(self, expr: Ge) -> int:
        return 1

    def visit_regex(self, expr: Regex) -> int:
        return 1

    def visit_in(self, expr: In) -> int:
        return 1

    def visit_is_null(self, expr: IsNull) -> int:
        return 1

    def visit_true(self, expr: Any) -> int:
        return 1

    def visit_false(self, expr: Any) -> int:
        return 1

    def visit_all(self, expr: AllExpr) -> int:
        return 1 + sum(e.accept(self) for e in expr.exprs)

    def visit_any(self, expr: AnyExpr) -> int:
        return 1 + sum(e.accept(self) for e in expr.exprs)

    def visit_not(self, expr: NotExpr) -> int:
        return 1 + expr.expr.accept(self)


class DictVisitor:
    """Visitor that converts expressions to dictionary representation."""

    def visit_eq(self, expr: Eq) -> dict[str, Any]:
        return {"type": "eq", "field": expr.field.name, "value": expr.value}

    def visit_ne(self, expr: Ne) -> dict[str, Any]:
        return {"type": "ne", "field": expr.field.name, "value": expr.value}

    def visit_lt(self, expr: Lt) -> dict[str, Any]:
        return {"type": "lt", "field": expr.field.name, "value": expr.value}

    def visit_le(self, expr: Le) -> dict[str, Any]:
        return {"type": "le", "field": expr.field.name, "value": expr.value}

    def visit_gt(self, expr: Gt) -> dict[str, Any]:
        return {"type": "gt", "field": expr.field.name, "value": expr.value}

    def visit_ge(self, expr: Ge) -> dict[str, Any]:
        return {"type": "ge", "field": expr.field.name, "value": expr.value}

    def visit_regex(self, expr: Regex) -> dict[str, Any]:
        result: dict[str, Any] = {
            "type": "regex",
            "field": expr.field.name,
            "pattern": expr.value,
        }
        if expr.flags is not None:
            result["flags"] = expr.flags
        return result

    def visit_in(self, expr: In) -> dict[str, Any]:
        return {"type": "in", "field": expr.field.name, "values": list(expr.values)}

    def visit_is_null(self, expr: IsNull) -> dict[str, Any]:
        return {
            "type": "is_null",
            "field": expr.field.name,
            "is_null": expr.is_null,
        }

    def visit_true(self, expr: Any) -> dict[str, Any]:
        return {"type": "true"}

    def visit_false(self, expr: Any) -> dict[str, Any]:
        return {"type": "false"}

    def visit_all(self, expr: AllExpr) -> dict[str, Any]:
        return {"type": "and", "exprs": [e.accept(self) for e in expr.exprs]}

    def visit_any(self, expr: AnyExpr) -> dict[str, Any]:
        return {"type": "or", "exprs": [e.accept(self) for e in expr.exprs]}

    def visit_not(self, expr: NotExpr) -> dict[str, Any]:
        return {"type": "not", "expr": expr.expr.accept(self)}


class FieldGathererVisitor:
    """Visitor that collects the names of all fields used in an expression tree."""

    def __init__(self) -> None:
        """Initialize the visitor with an empty set of field names."""
        self.field_names: set[str] = set()

    def visit_eq(self, expr: Eq) -> None:
        self.field_names.add(expr.field.name)

    def visit_ne(self, expr: Ne) -> None:
        self.field_names.add(expr.field.name)

    def visit_lt(self, expr: Lt) -> None:
        self.field_names.add(expr.field.name)

    def visit_le(self, expr: Le) -> None:
        self.field_names.add(expr.field.name)

    def visit_gt(self, expr: Gt) -> None:
        self.field_names.add(expr.field.name)

    def visit_ge(self, expr: Ge) -> None:
        self.field_names.add(expr.field.name)

    def visit_regex(self, expr: Regex) -> None:
        self.field_names.add(expr.field.name)

    def visit_in(self, expr: In) -> None:
        self.field_names.add(expr.field.name)

    def visit_is_null(self, expr: IsNull) -> None:
        self.field_names.add(expr.field.name)

    def visit_true(self, expr: Any) -> None:
        pass

    def visit_false(self, expr: Any) -> None:
        pass

    def visit_all(self, expr: AllExpr) -> None:
        for child in expr.exprs:
            child.accept(self)

    def visit_any(self, expr: AnyExpr) -> None:
        for child in expr.exprs:
            child.accept(self)

    def visit_not(self, expr: NotExpr) -> None:
        expr.expr.accept(self)


__all__ = [
    "StringVisitor",
    "CountVisitor",
    "DictVisitor",
    "FieldGathererVisitor",
]
