"""Strict new-mode tuning using existing scenario parsers, never saved settings."""
from app.multi_roi.errors import RoiError
from app.crowd_config import EVENT_PARAMETERS, validate_event_parameters
from app.scenario_parameters import sanitize, apply, legacy_projection_view


def compile_settings(code, raw, area, enabled):
    if type(raw) is not dict:
        raise RoiError('INVALID_RULE_CONFIG', field='parameters')
    values, ignored = sanitize(code, raw)
    if ignored:
        raise RoiError('INVALID_RULE_CONFIG', field='parameters')
    from app.event_cooldown import default_seconds
    cooldown = raw.get('cooldown_seconds', default_seconds())
    import math
    if type(cooldown) not in (int, float) or not math.isfinite(cooldown) or not 0 <= cooldown <= 300:
        raise RoiError('INVALID_RULE_CONFIG', field='cooldown_seconds')
    if code == 'CROWD':
        try:
            from app.crowd_config import CrowdConfig
            required = validate_event_parameters(raw) if enabled or any(k in raw for k in EVENT_PARAMETERS) else {}
            config = CrowdConfig.parse(dict(values, **required, enabled=enabled, event_enabled=enabled,
                                            roi=area.points, roi_id=str(area.roi_id), roi_name=area.label))
            return config.settings_payload(), float(cooldown)
        except (ValueError, TypeError, OverflowError):
            raise RoiError('INVALID_RULE_CONFIG', field='crowd.event_parameters') from None
    spec = {}
    request = dict(scenarioCode=code, enabled=enabled, parameters=raw,
                   rois=[dict(label=area.label, points=[list(p) for p in area.points])])
    try:
        accepted = apply(spec, request)
        if raw and not accepted and any(k != 'cooldown_seconds' for k in raw):
            raise ValueError('Invalid parameter combination.')
        projected = legacy_projection_view(spec, [request])
        if code == 'INTRUSION':
            from app.intrusion import IntrusionConfig
            settings = dict(spec.get('intrusion', {}), enabled=enabled, roi=area.points,
                            roi_id=str(area.roi_id), roi_name=area.label)
            settings = IntrusionConfig.parse(settings).payload()
        else:
            from app.region_scenario import project_loitering
            from app.fall_runtime import project_fall
            from app.fight_runtime import project_fight
            from app.fire_config import project_fire
            {'LOITERING': project_loitering, 'FALL': project_fall,
             'FIGHT': project_fight, 'FIRE': project_fire}[code](spec, projected)
            settings = spec.get(code.lower(), {'enabled': False})
            if code == 'FIRE' and 'scenario' not in settings:
                from app.fire_scenario import FireScenarioConfig
                settings['scenario'] = FireScenarioConfig().settings_payload()
            target = settings.get('scenario', settings) if code == 'FIRE' else settings
            target.update(roi_id=str(area.roi_id), roi_name=area.label)
        return settings, float(cooldown)
    except (ValueError, TypeError, KeyError, OverflowError):
        raise RoiError('INVALID_RULE_CONFIG', field='parameters') from None
