"""The module provides interpolators."""

from __future__ import annotations

import logging
from typing import Any

import numpy as np
import numpy.typing as npt
from scipy.interpolate import LinearNDInterpolator, NearestNDInterpolator

logger = logging.getLogger(__name__)


class Interpolator2D:
    """Two-dimensional interpolator."""

    def __init__(
        self,
        x: npt.NDArray[np.float64],
        y: npt.NDArray[np.float64],
        z: npt.NDArray[np.float64],
        kind: str = "linear",
        fill_value: float = np.nan,
    ):
        """

        Parameters
        ----------
        x :
            X-axis values (1-D array)
        y :
            Y-axis values (1-D array)
        z :
            Data values (1-D array)
        kind : {'nearest', 'linear'}
            The kind of interpolation to use.
        fill_value :
            Value used to fill in for requested points outside of the convex hull
            of the input points.

        """
        self.x = x
        self.y = y
        self.z = z

        self.kind = kind
        self.fill_value = fill_value

        self._interpolator = None

    @property
    def interpolator(self):
        """The actual interpolator."""
        if self._interpolator is None:
            if self.kind == "nearest":
                interp = NearestNDInterpolator((self.x, self.y), self.z)
            elif self.kind == "linear":
                interp = LinearNDInterpolator((self.x, self.y), self.z, self.fill_value)
            else:
                raise ValueError(f"Unknown interpolation method: {self.kind}")
            self._interpolator = interp
        return self._interpolator

    def update(self, parameters: dict[str, Any]):
        """Update the interpolator parameters."""
        for key, value in parameters.items():
            setattr(self, key, value)
        logger.info("The interpolator parameters have been updated.")
        self._interpolator = None

    def __call__(self, points: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
        """Evaluate interpolator."""
        return self.interpolator.__call__(points)
