# Copyright (c) ModelScope Contributors. All rights reserved.
import numpy as np
from transformers import TrainerControl, TrainerState
from typing import TYPE_CHECKING

from swift.utils import get_logger
from .base import TrainerCallback

if TYPE_CHECKING:
    from swift.trainers import Trainer, TrainingArguments

logger = get_logger()


class EarlyStopCallback(TrainerCallback):
    """An early stop implementation"""

    def __init__(self, args: 'TrainingArguments', trainer: 'Trainer'):
        super().__init__(args, trainer)
        self.best_metric = None
        self.interval = 0
        self.total_interval = args.early_stop_interval

    def on_save(self, args: 'TrainingArguments', state: TrainerState, control: TrainerControl, **kwargs):
        operator = np.greater if args.greater_is_better else np.less
        if self.best_metric is None or operator(state.best_metric, self.best_metric):
            self.best_metric = state.best_metric
            self.interval = 0
        else:
            self.interval += 1

        if self.interval >= self.total_interval:
            logger.info(f'Training stop because of eval metric is stable at step {state.global_step}')
            control.should_training_stop = True
