"""
bishop.kernel_methods – PRML Chapters 6 & 7
============================================
Wraps sklearn's SVM and Gaussian Process implementations.
Adds a KernelFactory helper for composing kernels as in PRML §6.

    from ml_ai_library.bishop.kernel_methods import (
        SVC, SVR,
        GaussianProcessRegressor, GaussianProcessClassifier,
        KernelPCA,
        KernelFactory,
    )
"""

from __future__ import annotations
# Re-export sklearn models directly ----------------------------------------
from sklearn.svm import SVC, SVR                                  # PRML §7.1
from sklearn.gaussian_process import (                             # PRML §6.4
    GaussianProcessRegressor,
    GaussianProcessClassifier,
)
from sklearn.gaussian_process.kernels import (
    RBF, Matern, DotProduct, WhiteKernel,
    ConstantKernel, ExpSineSquared, RationalQuadratic,
)
from sklearn.decomposition import KernelPCA                        # PRML §12.3


# ---------------------------------------------------------------------------
# Kernel composition helper (PRML §6.2)
# ---------------------------------------------------------------------------

class KernelFactory:
    """
    Convenience factory for building sklearn kernel objects that correspond
    to the compositions described in PRML §6.2.

    Example
    -------
    >>> k = KernelFactory.rbf(length_scale=1.0) + KernelFactory.white_noise()
    >>> gp  = GaussianProcessRegressor(kernel=k)
    """

    @staticmethod
    def rbf(length_scale: float = 1.0, amplitude: float = 1.0):
        """Squared exponential / RBF kernel  k(x,x') = σ² exp(-||x-x'||²/2l²)."""
        return ConstantKernel(amplitude) * RBF(length_scale)

    @staticmethod
    def matern(length_scale: float = 1.0, nu: float = 1.5):
        """Matérn kernel (nu controls smoothness)."""
        return Matern(length_scale=length_scale, nu=nu)

    @staticmethod
    def linear(sigma_b: float = 0.0):
        """Linear kernel  k(x,x') = x·x' + σ_b²."""
        return DotProduct(sigma_0=sigma_b)

    @staticmethod
    def periodic(length_scale: float = 1.0, periodicity: float = 1.0):
        """Periodic kernel for modelling repeating patterns."""
        return ExpSineSquared(length_scale=length_scale, periodicity=periodicity)

    @staticmethod
    def rational_quadratic(alpha: float = 1.0, length_scale: float = 1.0):
        """Rational quadratic kernel (scale-mixture of RBFs)."""
        return RationalQuadratic(alpha=alpha, length_scale=length_scale)

    @staticmethod
    def white_noise(noise_level: float = 1.0):
        """White noise kernel for additive i.i.d. noise."""
        return WhiteKernel(noise_level=noise_level)
