class CefrMapper:
    """Maps IRT theta values to CEFR levels and IELTS band scores."""

    THETA_TO_CEFR = [
        (-4.0, -2.5, 'pre_a1'),
        (-2.5, -1.5, 'a1'),
        (-1.5, -0.5, 'a2'),
        (-0.5, 0.5, 'b1'),
        (0.5, 1.5, 'b2'),
        (1.5, 2.5, 'c1'),
        (2.5, 4.0, 'c2'),
    ]

    CEFR_TO_BAND = {
        'pre_a1': 2.0,
        'a1': 3.0,
        'a2': 4.0,
        'b1': 5.0,
        'b2': 6.5,
        'c1': 7.5,
        'c2': 9.0,
    }

    CEFR_LABELS = {
        'pre_a1': 'Pre-A1 (Beginner)',
        'a1': 'A1 (Elementary)',
        'a2': 'A2 (Pre-Intermediate)',
        'b1': 'B1 (Intermediate)',
        'b2': 'B2 (Upper-Intermediate)',
        'c1': 'C1 (Advanced)',
        'c2': 'C2 (Proficient)',
    }

    @staticmethod
    def theta_to_cefr(theta):
        for low, high, level in CefrMapper.THETA_TO_CEFR:
            if low <= theta < high:
                return level
        return 'c2' if theta >= 2.5 else 'pre_a1'

    @staticmethod
    def theta_to_band(theta):
        cefr = CefrMapper.theta_to_cefr(theta)
        base_band = CefrMapper.CEFR_TO_BAND.get(cefr, 5.0)

        for low, high, level in CefrMapper.THETA_TO_CEFR:
            if level == cefr:
                range_width = high - low
                if range_width > 0:
                    position = (theta - low) / range_width
                else:
                    position = 0.5

                cefr_list = list(CefrMapper.CEFR_TO_BAND.keys())
                idx = cefr_list.index(cefr)
                next_band = CefrMapper.CEFR_TO_BAND.get(
                    cefr_list[min(idx + 1, len(cefr_list) - 1)], base_band + 1.0
                )

                band = base_band + position * (next_band - base_band)
                return round(band * 2) / 2

        return base_band

    @staticmethod
    def band_to_cefr(band):
        if band < 2.5:
            return 'pre_a1'
        if band < 3.5:
            return 'a1'
        if band < 4.5:
            return 'a2'
        if band < 5.5:
            return 'b1'
        if band < 7.0:
            return 'b2'
        if band < 8.0:
            return 'c1'
        return 'c2'

    @staticmethod
    def get_cefr_label(cefr_code):
        return CefrMapper.CEFR_LABELS.get(cefr_code, cefr_code)
