from __future__ import annotations
from typing import Dict
import polars as pl
from tools.base import BaseTool


class MultiFieldFormulaTool(BaseTool):
    """Apply a single expression to multiple selected fields."""

    def execute(self, inputs: Dict[str, pl.DataFrame]) -> Dict[str, pl.DataFrame]:
        df = inputs.get("Input", pl.DataFrame())
        if self.config is None or df.is_empty():
            return {"Output": df}

        expr_text = self._cfg("Expression", "") or ""
        alteryx_type = self._cfg("OutputType", "") or ""
        size = self._cfg("OutputSize")
        dtype = self.ctx.type_mapper.map(alteryx_type) if alteryx_type else None

        field_filter_type = self._cfg("Fields/@type") or ""
        selected_fields = [
            f.attrib["name"]
            for f in self.config.findall("Fields/Field")
            if f.attrib.get("selected", "True") == "True"
            and f.attrib["name"] in df.columns
        ]

        # If no explicit field list, apply to all fields of matching type
        if not selected_fields and field_filter_type:
            type_map_rev = {
                "Number": [pl.Float32, pl.Float64, pl.Int16, pl.Int32, pl.Int64],
                "String": [pl.String, pl.Utf8],
            }
            target_types = type_map_rev.get(field_filter_type, [])
            selected_fields = [
                c for c in df.columns
                if any(df[c].dtype == t for t in target_types)
            ]

        if not selected_fields:
            return {"Output": df}

        for field in selected_fields:
            # Replace [_CurrentField_] placeholder with actual column name
            actual_expr = expr_text.replace("[_CurrentField_]", f"[{field}]")
            target_dtype = dtype or df[field].dtype
            try:
                series = self.ctx.transpiler.eval_series(df, actual_expr, field, target_dtype)
                df = df.with_columns(series.alias(field))
            except Exception as e:
                raise RuntimeError(
                    f"MultiFieldFormula field {field!r}: {e}"
                ) from e

        return {"Output": df}
