code: def _fit_and_score(
      pipeline: ForecastingPipeline,
      y: pd.Series,
      X: Optional[Union[pd.Series, pd.DataFrame]],
      scoring: Dict[str, Union[str, _PredictScorer]],
      train: np.ndarray,
      test: np.ndarray,
      parameters: Optional[Dict[str, Any]],
      fit_params: Dict[str, Any],
      return_train_score: bool,
      alpha: Optional[float],
      coverage: Union[float, List[float]],
      error_score=0,
      **additional_scorer_kwargs,
  ) -> Tuple[
      Dict[str, float], float, float, Union[pd.PeriodIndex, Any]
  ]:
      """Fits the pipeline on a single train split and scores on the test split
      Similar to _fit_and_score from `sklearn` [1] (and to some extent `sktime` [2]).
      Difference is that [1] operates on a single fold only, whereas [2] operates on all cv folds.
      Ref:
      [1] https://github.com/scikit-learn/scikit-learn/blob/0.24.1/sklearn/model_selection/_validation.py#L449
      [2] https://github.com/sktime/sktime/blob/v0.5.3/sktime/forecasting/model_selection/_tune.py#L95
  
      Parameters
      ----------
      pipeline : ForecastingPipeline
          Forecasting Pipeline that needs to be fitted and scored.
      y : pd.Series
          Target variable values that need to be used for forecasting. This should be the
          untransformed (original) values. Transformation will happen in the fitting process.
      X : Optional[Union[pd.Series, pd.DataFrame]]
          Exogenous Variable values to be used for forecasting. This should be the
          untransformed (original) values. Transformation will happen in the fitting process.
      scoring : Dict[str, Union[str, _PredictScorer]]
          Scoring Dictionary. Values can be valid strings that can be converted to
          callable metrics or the callable metrics directly
          e.g.
              {
                  'mae': make_scorer(mean_absolute_error, greater_is_better=False)
                  ,'r2': make_scorer(r2_score)
              }
      train : np.ndarray
          Indices of training samples (integer based indexing).
      test : np.ndarray
          Indices of test samples (integer based indexing).
      parameters : Optional[Dict[str, Any]]
          Parameter to set for the pipeline. e.g.
          {'forecaster__model__use_boxcox': True, 'forecaster__model__trend': 'mul'}
      fit_params : Dict[str, Any]
          Fit parameters to be used when training the model
          e.g. {'fh': ForecastingHorizon([1, 2, 3], is_relative=True)}
      return_train_score : bool
          Should the training scores be returned. Unused for now.
      alpha: Optional[float]
          The alpha (quantile) value to use for the point predictions.
      coverage: Union[float, List[float]]
          The coverage to be used for prediction intervals.
      error_score : float, optional
          Unused for now, by default 0
      **additional_scorer_kwargs: Dict[str, Any]
          Additional scorer kwargs such as {`sp`:12} required by metrics like MASE
  
      Returns
      -------
      Tuple[Dict[str, float], float, float, Union[pd.PeriodIndex, Any]]
          In order
          (1) Metrics: e.g. {'mae': 31.66, 'rmse': 38.18, 'mape': 0.083}
          (2) Fit Time Taken
          (3) Score Time taken
          (4) Cutoff Index value between training and test (based on `train` and `test`
              arguments), e.g. Period('1956-12', 'M')
  
      Raises
      ------
      ValueError
          When test indices do not match predicted indices. This is only for
          for internal checks and should not be raised when used by external users
      """
      if parameters is not None:
          pipeline.set_params(**parameters)
  
      y_imputed, _ = _get_imputed_data(pipeline=pipeline, y=y, X=X)
  
      # We need to expand test indices to a full range, since some forecasters
      # require the full range of exogenous values. This comes into picture when
      # FH has gaps (e.g. [2, 3]). In that case, some forecasters still need the
      # exogenous variable values at FH = 1
      # Refer:
      # https://github.com/sktime/sktime/issues/2598#issuecomment-1203308542
      # https://github.com/sktime/sktime/blob/4164639e1c521b112711c045d0f7e63013c1e4eb/sktime/forecasting/model_evaluation/_functions.py#L196
      test_expanded = np.arange(train[-1], test[-1]) + 1
  
      # y_train, X_train, X_test can have missing values since pipeline will impute them
      y_train = y.iloc[train]
      X_train = None if X is None else X.iloc[train]
      X_test = None if X is None else X.iloc[test_expanded]
  
      # y_test is "y_true" and used for metrics, hence it can not have missing values
      # Hence using y_imputed
      # Refer to: https://github.com/pycaret/pycaret/issues/2369
      y_test_imputed = y_imputed.iloc[test]
      y_train_imputed = y_imputed.iloc[
          train
      ]  # Needed for MASE, RMSSE, etc.
  
      if y_test_imputed.isna().sum() != 0:
          raise ValueError(
              "\ny_test has missing values. This condition should not have occurred. "
              "\nPlease file a report issue on GitHub with a reproducible example of "
              "how this condition was generated."
              "\nhttps://github.com/pycaret/pycaret/issues/new/choose"
          )
  
      # Fit the forecaster ----
      start = time.time()
      try:
          pipeline.fit(y_train, X_train, **fit_params)
      except Exception as error:
          logger.error(f"Fit failed on {pipeline}")
          logger.error(error)
  
          if error_score == "raise":
              raise
  
      fit_time = time.time() - start
  
      # Determine Cutoff ----
      # NOTE: Cutoff is available irrespective of whether fit passed or failed
      cutoff = pipeline.cutoff[0]
  
      # Score the model ----
      lower = pd.Series(dtype="float64")
      upper = pd.Series(dtype="float64")
      if pipeline.is_fitted:
          y_pred, lower, upper = get_predictions_with_intervals(
              forecaster=pipeline,
              alpha=alpha,
              coverage=coverage,
              X=X_test,
          )
  
          if (y_test_imputed.index.values != y_pred.index.values).any():
              print(
                  f"\t y_train: {y_train.index.values},"
                  f"\n\t y_test: {y_test_imputed.index.values}"
              )
              print(f"\t y_pred: {y_pred.index.values}")
              raise ValueError(
                  "y_test indices do not match y_pred_indices or split/prediction "
                  "length does not match forecast horizon."
              )
  
      start = time.time()
      fold_scores = {}
      scoring = _get_metrics_dict(scoring)
  
      # SP should be passed from outside in additional_scorer_kwargs already
      additional_scorer_kwargs = update_additional_scorer_kwargs(
          initial_kwargs=additional_scorer_kwargs,
          y_train=y_train_imputed,
          lower=lower,
          upper=upper,
      )
      for scorer_name, scorer in scoring.items():
          if pipeline.is_fitted:
              # get all kwargs in additional_scorer_kwargs
              # that correspond to parameters in function signature
              kwargs = {
                  **{
                      k: v
                      for k, v in additional_scorer_kwargs.items()
                      if k in get_function_params(scorer._score_func)
                  },
                  **scorer._kwargs,
              }
              try:
                  metric = scorer._score_func(
                      y_true=y_test_imputed, y_pred=y_pred, **kwargs
                  )
              except Exception:
                  # Missing values in y_train will cause MASE to fail.
                  metric = np.nan
          else:
              metric = np.nan
          fold_scores[scorer_name] = metric
      score_time = time.time() - start
  
      return fold_scores, fit_time, score_time, cutoff
  
imports: import time
  import warnings
  from collections import defaultdict
  from functools import partial
  from typing import Any, Dict, Generator, List, Optional, Tuple, Union
  import numpy
  import pandas
  from joblib import Parallel, delayed
  from scipy.stats import rankdata
  from sklearn.base import clone
  from sklearn.metrics._scorer import _PredictScorer
  from sklearn.model_selection import ParameterGrid, ParameterSampler, check_cv
  from sklearn.model_selection._validation import _aggregate_score_dicts
  from sktime.forecasting.compose import ForecastingPipeline
  from sktime.forecasting.model_selection import ExpandingWindowSplitter, SlidingWindowSplitter
  from sktime.utils.validation.forecasting import check_y_X
  from pycaret.internal.logging import get_logger
  from pycaret.utils.generic import _get_metrics_dict, get_function_params
  from pycaret.utils.time_series.forecasting import get_predictions_with_intervals, update_additional_scorer_kwargs
  from pycaret.utils.time_series.forecasting.pipeline import _get_imputed_data
label_desc: Use image node_id 2 for calling a global function with example usage: _fit_and_score(pipeline, y, X, scoring, train, test, parameters, fit_params, return_train_score, alpha, coverage, error_score) and returns: fold_scores,  fit_time,  score_time,  cutoff