from db import query_db, execute_db
from datetime import datetime

def execute_pipeline(actions, barcode, context):
    """
    Executes the chain of actions defined in the Rule.
    Returns: {'success': bool, 'message': str, 'data': dict}
    """
    field_values = {}
    should_save = False
    
    for action in actions:
        atype = action.get('type')

        # --- MAP (Extract) ---
        if atype == 'map':
            start = int(action.get('start', 1)) - 1
            end = int(action.get('end', len(barcode)))
            target = action.get('field')
            if target:
                safe_end = min(end, len(barcode))
                if start < len(barcode):
                    field_values[target] = barcode[start:safe_end]

        # --- CLEAN (Format) ---
        elif atype == 'clean':
            target = action.get('field')
            func = action.get('func')
            if target in field_values:
                val = str(field_values[target])
                if func == 'TRIM': field_values[target] = val.strip()
                elif func == 'REMOVE_SPACES': field_values[target] = val.replace(" ", "")
                elif func == 'UPPERCASE': field_values[target] = val.upper()
                elif func == 'REMOVE_LEADING_ZEROS': field_values[target] = val.lstrip('0')

        # --- DUPLICATE CHECK (The Gatekeeper) ---
        elif atype == 'duplicate':
            target = action.get('field')
            behavior = action.get('behavior', 'WARN') # Default to WARN
            val = field_values.get(target)
            
            if val:
                # 1. Check DB
                same_sess = query_db(f"SELECT id FROM {context['table_name']} WHERE {target} = ? AND session_id = ? AND is_deleted=0", [val, context['session_id']], one=True)
                other_sess = query_db(f"SELECT id FROM {context['table_name']} WHERE {target} = ? AND is_deleted=0", [val], one=True)

                is_dup = False
                dup_msg = ""
                
                if same_sess:
                    is_dup = True
                    dup_msg = f"Already scanned in THIS session ({val})"
                    field_values['duplicate_status'] = 'dup_same_session'
                    field_values['duplicate_info'] = 'Duplicate in same session'
                elif other_sess:
                    is_dup = True
                    dup_msg = f"Previously scanned in another session ({val})"
                    field_values['duplicate_status'] = 'dup_other_session'
                    field_values['duplicate_info'] = 'Duplicate from history'
                else:
                    field_values['duplicate_status'] = 'normal'
                    field_values['duplicate_info'] = None

                # 2. Enforce Behavior
                if is_dup:
                    if behavior == 'BLOCK':
                        # STRICT MODE: Stop immediately.
                        return {
                            'success': False, 
                            'message': f"⛔ STRICT MODE: {dup_msg}. Entry denied.",
                            'data': field_values
                        }
                    
                    elif behavior == 'WARN':
                        # WARN MODE: Ask user, unless they already clicked "Yes"
                        if not context.get('confirm_duplicate'):
                            return {
                                'success': False, 
                                'needs_confirmation': True,
                                'message': f"⚠️ {dup_msg}", 
                                'data': field_values
                            }
        # --- USER INPUT (The Gatekeeper) ---
        elif atype == 'input':
            # 1. Check if we received the manual data (Weight) from the Save button
            incoming_data = context.get('extra_data')
            
            # 2. If data exists, MERGE it and CONTINUE (Don't stop!)
            if incoming_data:
                # Update our main data list with the user's input (e.g. weight=164)
                field_values.update(incoming_data)
                continue # <--- RESUME PIPELINE (Goes to next rule, usually SAVE)
            
            # 3. If no data, STOP and ask for it
            return {
                'success': False, 
                'needs_input': True,
                'message': 'Opening Details Form...',
                'data': field_values
            }
        
        # --- SAVE MARKER ---
        elif atype == 'save':
            should_save = True

    # --- RESULT ---
    if should_save:
        try:
            # Commit to DB
            cols = ['session_id', 'scanned_by', 'scanned_at']
            vals = [context['session_id'], context['user_id'], datetime.now()]
            
            for k, v in field_values.items():
                cols.append(k)
                vals.append(v)
            
            placeholders = ', '.join(['?'] * len(cols))
            sql = f"INSERT INTO {context['table_name']} ({', '.join(cols)}) VALUES ({placeholders})"
            new_id = execute_db(sql, vals)

            return {'success': True, 'message': 'Saved Successfully', 'detail_id': new_id, 'data': field_values}
        except Exception as e:
            return {'success': False, 'message': f"Database Error: {str(e)}", 'data': field_values}
    else:
        return {'success': True, 'message': f"✅ Parsed: {field_values} (No Save Action)", 'data': field_values}