"""
Wrapper module for filter_short_groups implementations.
This provides a consistent interface regardless of which implementation is available.
"""
import time
import numpy as np

# Try to import the C implementation first
try:
    from filter_short_groups import filter_short_groups_c
    USE_C_IMPLEMENTATION = True
    print("Using optimized C implementation of filter_short_groups")
except ImportError:
    USE_C_IMPLEMENTATION = False
    print("C implementation not available, falling back to NumPy implementation")

def filter_short_groups_numpy(presence_list, filter_size, device_id, dates_str):
    """
    Original NumPy implementation, kept for fallback and comparison.
    """
    # Start timer for benchmarking
    st = time.time()

    if not presence_list or filter_size <= 1:
        print(f"NumPy Optimized: Early exit/no processing time: {time.time() - st:.6f}s")
        return presence_list[:] if isinstance(presence_list, list) else list(presence_list)

    result = np.array(presence_list, dtype=float)
    n = len(result)

    previous_states = set()

    while True:
        # Cycle detection
        current_state_tuple = tuple(result)
        if current_state_tuple in previous_states:
            print("NumPy Optimized: Cycle detected, breaking.")
            break
        previous_states.add(current_state_tuple)

        # 1. Calculate the sign of each element (-1, 0, 1)
        signs = np.sign(result)

        # 2. Find indices where the sign changes
        change_indices = np.where(np.diff(signs) != 0)[0] + 1

        # 3. Define the boundaries of all consecutive runs
        boundaries = np.concatenate(([0], change_indices, [n]))

        # If there's only one segment, no further processing is needed.
        if len(boundaries) <= 2:
            break

        # 4. Vectorized extraction of run properties
        run_starts = boundaries[:-1]
        run_ends = boundaries[1:]
        run_lengths = run_ends - run_starts
        run_signs = signs[run_starts]

        # 5. Identify short runs and collect their properties
        short_runs_to_process = []
        for i in range(len(run_starts)):
            if run_lengths[i] > 0 and run_lengths[i] < filter_size:
                short_runs_to_process.append({
                    'start': run_starts[i],
                    'end': run_ends[i],
                    'sign': run_signs[i],
                    'length': run_lengths[i]
                })

        # 6. Check if any modifiable short runs were found
        if not short_runs_to_process:
            break

        # 7. Sort the short runs: shortest first, then by start index for determinism
        short_runs_to_process.sort(key=lambda r: (r['length'], r['start']))

        # 8. Process ONLY the *first* (shortest) identified run in this pass
        run_to_process = short_runs_to_process[0]
        start = run_to_process['start']
        end = run_to_process['end']
        run_sign = run_to_process['sign']

        # Determine the replacement value
        replacement_value = 1.0 if run_sign == 0 else 0.0

        # 9. Apply the replacement
        result[start:end] = replacement_value

    # End timer and print
    print(f"filter_short_groups_numpy time: {time.time() - st:.6f}s")

    return result.tolist()

def filter_short_groups(presence_list, filter_size, device_id, dates_str):
    """
    Main entry point that automatically selects the best available implementation.
    """
    if USE_C_IMPLEMENTATION:
        return filter_short_groups_c(presence_list, filter_size, device_id, dates_str)
    else:
        return filter_short_groups_numpy(presence_list, filter_size, device_id, dates_str)
