import json
import logging
import os

from pypulseq import Sequence

from seq_interp.src.hardware.constraints import HardwareConstraints


class PulseqLoader:
    """
    Адаптер для загрузки последовательностей в формате Pulseq (.seq файлы).
    """

    def __init__(self, hw: HardwareConstraints):
        self.hw = hw
        self.logger = logging.getLogger("PulseqLoader")

    def load(self, path: str) -> dict:
        """
        Читает Pulseq-файл и возвращает структуру данных последовательности.
        """
        seq = Sequence(system=self.hw)
        seq.read(path)

        blocks = self._parse_blocks(seq)
        waveforms = seq.waveforms_export()
        params = self._load_params(path)

        seq_data = {
            "blocks": blocks,
            "sequence": seq,
            "params": params,
        }
        seq_data.update(waveforms)

        self.logger.info(
            "Файл %s загружен. Осталось %d блоков после удаления нулевой длительности.",
            path,
            len(blocks),
        )
        return seq_data

    def _load_params(self, seq_path: str) -> dict:
        json_path = os.path.splitext(seq_path)[0] + ".json"
        defaults = {
            "G_amp_max": self.hw.GRAD_MAX,
            "grad_raster_time": self.hw.grad_raster_time,
            "rf_raster_time": self.hw.rf_raster_time,
            "gamma": self.hw.gamma,
            "scale_rf": 1.0,
        }
        if not os.path.exists(json_path):
            return defaults

        with open(json_path, "r", encoding="utf-8") as f:
            loaded = json.load(f)
        defaults.update(loaded)
        return defaults

    def _parse_blocks(self, seq) -> list:
        """
        Формирует список блоков из объекта Sequence.

        Работает по сырой таблице событий seq.block_events (столбцы:
        [?, RF, GX, GY, GZ, ADC, EXT]) — без seq.get_block(), который
        реконструирует объекты событий и распаковывает shape'ы на каждый
        блок и на больших последовательностях доминирует по времени.
        """
        blocks = []
        for block_id, events in seq.block_events.items():
            duration = seq.block_durations[block_id]
            if duration == 0:
                self.logger.warning(
                    "Удалён блок (ID: %d) с нулевой длительностью.",
                    block_id,
                )
                continue

            block_type = []
            has_adc = False
            if events[1]:
                block_type.append("RF")
            if events[5]:
                block_type.append("ADC")
                has_adc = True
            if any(events[2:5]):
                block_type.append("GRAD")

            blocks.append({
                "type": block_type,
                "duration": duration,
                "has_adc": has_adc,
            })

        return blocks
