import json
import re
from app.extensions import db
from app.models.lv import LVPosition


def execute_rules(form_data, rules_json, company_id):
    rules = json.loads(rules_json) if isinstance(rules_json, str) else rules_json
    positions = []

    for rule in rules:
        if not _evaluate_conditions(rule.get('conditions', {}), form_data):
            continue
        for action in rule.get('actions', []):
            pos = _create_position(action, form_data, company_id)
            if pos:
                positions.append(pos)

    return positions


def _evaluate_conditions(conditions, form_data):
    if not conditions or not conditions.get('items'):
        return True

    operator = conditions.get('operator', 'and')
    items = conditions.get('items', [])

    results = []
    for cond in items:
        field = cond.get('field', '')
        op = cond.get('operator', 'eq')
        value = cond.get('value', '')
        value2 = cond.get('value2', '')
        raw = form_data.get(field, '')

        if op == 'is_checked':
            results.append(raw == 'an')
        elif op == 'is_empty':
            results.append(raw == '' or raw is None)
        elif op == 'not_empty':
            results.append(raw != '' and raw is not None)
        else:
            try:
                f_val = _to_float(raw)
                f_cond = _to_float(value)
                if op == 'eq':
                    results.append(f_val == f_cond)
                elif op == 'neq':
                    results.append(f_val != f_cond)
                elif op == 'gt':
                    results.append(f_val > f_cond)
                elif op == 'gte':
                    results.append(f_val >= f_cond)
                elif op == 'lt':
                    results.append(f_val < f_cond)
                elif op == 'lte':
                    results.append(f_val <= f_cond)
                elif op == 'between':
                    f_val2 = _to_float(value2)
                    results.append(f_cond <= f_val <= f_val2)
                else:
                    results.append(str(raw) == str(value))
            except (ValueError, TypeError):
                results.append(str(raw) == str(value))

    if operator == 'or':
        return any(results)
    return all(results)


def _create_position(action, form_data, company_id):
    pos_nr = action.get('pos_nr', '')
    if not pos_nr:
        return None

    lv_lookup = action.get('lv_lookup', True)
    columns = action.get('columns', {})

    # Default values
    pos = {
        'pos_nr': pos_nr,
        'kurztext': '',
        'einheit': 'ST',
        'menge': 1,
        'faktor': 1,
        'laenge': 0,
        'breite': 0,
        'tiefe': 0,
        'bemerkung': '',
        'einzelpreis': 0,
    }

    # LV lookup
    if lv_lookup:
        lv_pos = LVPosition.query.filter_by(company_id=company_id, pos_nr=pos_nr).first()
        if lv_pos:
            pos['kurztext'] = lv_pos.kurztext or ''
            pos['einheit'] = lv_pos.einheit or 'ST'
            pos['einzelpreis'] = lv_pos.einzelpreis or 0

    # Apply overrides
    for col_key, col_def in columns.items():
        if col_key not in pos and col_key != 'pos_nr':
            continue
        val = _resolve_value(col_def, form_data)
        if val is not None:
            if col_key in ('menge', 'faktor', 'laenge', 'breite', 'tiefe', 'einzelpreis'):
                pos[col_key] = _to_float(val)
            else:
                pos[col_key] = str(val)

    return pos


def _resolve_value(col_def, form_data):
    if not col_def:
        return None
    ctype = col_def.get('type', 'fixed')
    value = col_def.get('value', '')

    if ctype == 'fixed':
        return value
    elif ctype == 'field':
        return form_data.get(value, '')
    elif ctype == 'formula':
        return _eval_formula(value, form_data)
    return value


def _eval_formula(expr, form_data):
    expr = str(expr)
    def _replace_field(m):
        fname = m.group(1)
        raw = form_data.get(fname, '0')
        return str(raw).replace(',', '.')
    expr = re.sub(r'\[([^\]]+)\]', _replace_field, expr)
    safe = re.sub(r'[^\d\+\-\*\/\(\)\. ]', '', expr)
    if not safe.strip():
        return 0
    try:
        return eval(safe, {'__builtins__': {}}, {})
    except Exception:
        return 0


def _to_float(val):
    if val is None or val == '':
        return 0.0
    return float(str(val).replace(',', '.').replace(' ', ''))
