from __future__ import annotations

import numpy as np

from backend.node_registry import register_node
from backend.data_types import DataField


@register_node(display_name="Gradient")
class Gradient:
    @classmethod
    def INPUT_TYPES(cls):
        return {
            "required": {
                "field": ("DATA_FIELD",),
                "component": (["magnitude", "x", "y", "azimuth"],),
            }
        }

    OUTPUTS = (
        ('DATA_FIELD', 'gradient'),
    )
    FUNCTION = "process"

    DESCRIPTION = (
        "Compute the spatial gradient using a Sobel operator. "
        "'x'/'y' give the physical gradient components (z_unit/xy_unit); "
        "'magnitude' gives sqrt(gx²+gy²); "
        "'azimuth' gives the local slope direction in radians via atan2(gy, gx). "
    )

    KEYWORDS = ("sobel", "slope", "derivative", "azimuth")

    def process(self, field: DataField, component: str) -> tuple:
        from backend.nodes.surface_common import physical_sobel_gradient, slope_unit

        gx, gy = physical_sobel_gradient(field)

        if component == "magnitude":
            result = np.hypot(gx, gy)
            out_unit_z = slope_unit(field)
        elif component == "x":
            result = gx
            out_unit_z = slope_unit(field)
        elif component == "y":
            result = gy
            out_unit_z = slope_unit(field)
        elif component == "azimuth":
            result = np.arctan2(gy, gx)
            out_unit_z = "rad"
        else:
            raise ValueError(f"Unknown gradient component: {component!r}")

        return (field.replace(data=result, si_unit_z=out_unit_z),)
