def select_best_model(
        ts: TimeSeries,
        thetas: Optional[list[int]] = None,
        m: Optional[int] = None,
        normalization: bool = True,
        n_jobs: int = 1,
    ) -> "FourTheta":
        """
        Performs a grid search over all hyper parameters to select the best model,
        using the fitted values on the training series `ts`.


        Uses 'LocalForecastingModel.gridsearch' with 'use_fitted_values=True' and 'metric=metrics.mae`.

        Parameters
        ----------
        ts
            The TimeSeries on which the model will be tested.
        thetas
            A list of thetas to loop over. Defaults to [1, 2, 3].
        m
            Optionally, the season used to decompose the time series.
        normalization
            If `True`, the data is normalized so that the mean is 1. Defaults to `True`.
        n_jobs
            The number of jobs to run in parallel. Parallel jobs are created only when there are two or more theta
            values to be evaluated. Each job will instantiate, train, and evaluate a different instance of the model.
            Defaults to `1` (sequential). Setting the parameter to `-1` means using all the available cores.

        Returns
        -------
        FourTheta
            The best performing model on the time series.
        """
        # Only import if needed
        from darts.metrics import mae

        if thetas is None:
            thetas = [1, 2, 3]
        if (ts.values(copy=False) <= 0).any():
            drift_mode = [TrendMode.LINEAR]
            model_mode = [ModelMode.ADDITIVE]
            season_mode = [SeasonalityMode.ADDITIVE]
            logger.warning(
                "The given TimeSeries has negative values. The method will only test "
                "linear trend and additive modes."
            )
        else:
            season_mode = [season for season in SeasonalityMode]
            model_mode = [model for model in ModelMode]
            drift_mode = [trend for trend in TrendMode]

        theta = FourTheta.gridsearch(
            {
                "theta": thetas,
                "model_mode": model_mode,
                "season_mode": season_mode,
                "trend_mode": drift_mode,
                "seasonality_period": [m],
                "normalization": [normalization],
            },
            ts,
            use_fitted_values=True,
            metric=mae,
            n_jobs=n_jobs,
        )
        return theta

        Performs a grid search over all hyper parameters to select the best model,
        using the fitted values on the training series `ts`.


        Uses 'LocalForecastingModel.gridsearch' with 'use_fitted_values=True' and 'metric=metrics.mae`.

        Parameters
        ----------
        ts
            The TimeSeries on which the model will be tested.
        thetas
            A list of thetas to loop over. Defaults to [1, 2, 3].
        m
            Optionally, the season used to decompose the time series.
        normalization
            If `True`, the data is normalized so that the mean is 1. Defaults to `True`.
        n_jobs
            The number of jobs to run in parallel. Parallel jobs are created only when there are two or more theta
            values to be evaluated. Each job will instantiate, train, and evaluate a different instance of the model.
            Defaults to `1` (sequential). Setting the parameter to `-1` means using all the available cores.

        Returns
        -------
        FourTheta
            The best performing model on the time series.
        
darts/models/forecasting/theta.py