import json


class HardwareConstraints:
    """
    Класс, хранящий аппаратные ограничения и настройки MRI-системы.
    Может инициализироваться из JSON-файла.
    """

    def __init__(self, json_path: str = None):
        # Значения по умолчанию (совместимые с pypulseq)
        self.rf_raster_time = 1e-6  # сек, шаг временной дискретизации RF
        self.grad_raster_time = 10e-6  # сек, шаг дискретизации градиента
        self.adc_raster_time = 100e-9  # сек, шаг дискретизации АЦП
        self.block_duration_raster = 10e-6  # сек, шаг дискретизации длительности блока

        # Системные ограничения (по умолчанию отсутствуют задержки мертвого времени)
        self.rf_dead_time = 0.0
        self.rf_ringdown_time = 0.0
        self.adc_dead_time = 0.0
        self.gamma = 42.576e6  # Гиромагнитное отношение (Гц/Т) для протона

        # Кастомные параметры системы
        self.TR_DELAY = 20e-9  # сек, задержка после съема (между TR)
        self.RF_DELAY = 500e-6  # сек, задержка перед RF-импульсом
        self.START_DELAY = 17e-6  # сек, начальная задержка перед последовательностью
        self.MIN_BLOCK_DURATION = 20e-9  # сек, минимальная длительность блока (квант времени последовательности)
        self.GRAD_DELAY = 1000e-9

        # Флаги вставки задержек в синхро-последовательность.
        # Если флаг False — соответствующий блок задержки не вставляется
        # (и не вычитается из соседнего), что убирает артефакты 1/0 тактов.
        self.TR_DELAY_ENABLED = True
        self.RF_DELAY_ENABLED = True
        self.START_DELAY_ENABLED = True

        # Максимальные амплитуды
        self.RF_MAX = 1.0  # относительная макс. амплитуда RF (нормирована на 1.0)
        self.GRAD_MAX = 9e-3 * self.gamma  # макс. градиент (Гц/м) по умолчанию 9 mT/m * gamma

        # Загрузка параметров из JSON при указании пути
        if json_path:
            self.load_from_json(json_path)

    def load_from_json(self, json_path: str):
        """
        Загружает параметры аппаратных ограничений из JSON-файла.
        """
        with open(json_path, 'r') as f:
            data = json.load(f)
        # Обновление обязательных параметров (если указаны в файле)
        self.rf_raster_time = data.get("rf_raster_time", self.rf_raster_time)
        self.grad_raster_time = data.get("grad_raster_time", self.grad_raster_time)
        self.adc_raster_time = data.get("adc_raster_time", self.adc_raster_time)
        self.block_duration_raster = data.get("block_duration_raster", self.block_duration_raster)
        self.rf_dead_time = data.get("rf_dead_time", self.rf_dead_time)
        self.rf_ringdown_time = data.get("rf_ringdown_time", self.rf_ringdown_time)
        self.adc_dead_time = data.get("adc_dead_time", self.adc_dead_time)
        self.gamma = data.get("gamma", self.gamma)
        # Обновление пользовательских параметров
        self.TR_DELAY = data.get("TR_DELAY", self.TR_DELAY)
        self.RF_DELAY = data.get("RF_DELAY", self.RF_DELAY)
        if self.rf_raster_time == 0.5e-6:
            self.START_DELAY = 885 * self.MIN_BLOCK_DURATION
        elif self.rf_raster_time == 0.05e-6:
            self.START_DELAY = 89 * self.MIN_BLOCK_DURATION
        else:
            self.START_DELAY = self.MIN_BLOCK_DURATION * 10
        self.MIN_BLOCK_DURATION = data.get("MIN_BLOCK_DURATION", self.MIN_BLOCK_DURATION)
        # Флаги вставки задержек
        self.TR_DELAY_ENABLED = data.get("TR_DELAY_ENABLED", self.TR_DELAY_ENABLED)
        self.RF_DELAY_ENABLED = data.get("RF_DELAY_ENABLED", self.RF_DELAY_ENABLED)
        self.START_DELAY_ENABLED = data.get("START_DELAY_ENABLED", self.START_DELAY_ENABLED)
        # Обновление максимальных амплитуд (если указаны)
        self.RF_MAX = data.get("RF_MAX", self.RF_MAX)
        self.GRAD_MAX = data.get("GRAD_MAX", self.GRAD_MAX)
