import numpy as np

def trigger_veq02(env_fct, charfct_ori, thres1, thres2, fs, tsmth, thresh_off_env):

    charfct = np.log10(charfct_ori)                     # convert STA - LTA ratios from linear scale to log10 scale
    ind1 = np.where(charfct > thres1)[0]                # find indices where STA - LTA exceeds threshold on

    if ind1.size == 0:                                  # In case there is no STA - LTA that exceeds threshold on
        trg_on = []
        val_on = []
        trg_off = []
        val_off = []
        return trg_on, val_on, trg_off, val_off         # Return empty values

    on_first = ind1[0]
    on_diff = ind1[np.where(np.diff(ind1) > 1)[0] + 1]               # preserve only the first breaks
    pick_on = np.concatenate((on_first, on_diff), axis=None)  #

    true_off = np.zeros(len(pick_on), dtype=int)
    idx_off = true_off

    # ==================================================================================================================
    # Smoothing STA-LTA Series
    charfct2_ser = charfct.rolling(window=int(tsmth*fs), min_periods=1, center=True).median()
    charfct2 = charfct2_ser.to_numpy()
    # ==================================================================================================================

    # ==================================================================================================================
    # Protocol to Find the End of the Waveform (When the Smoothed STA - LTA crosses Threshold Off the 2nd Time

    for k in range(len(pick_on)):
        char_on = charfct2[pick_on[k]]
        l = 1

        while char_on > thres2:
            if charfct2[pick_on[k]] == charfct2[-1]:
                l = 0
                break

            char_on = charfct2[pick_on[k] + l]

            if char_on == charfct2[-1]:
                break

            l = l + 1

        false_off_old = char_on                       # This is when the STA - LTA ratio crosses threshold off 1st time
        err = -1
        ll = l

        while err <= 0 and (charfct2[pick_on[k] + ll]  < thres2):
            if charfct2[pick_on[k]] == charfct2[-1]:
                ll = 0
                break

            false_off_new = charfct2[pick_on[k] + ll]

            if false_off_new == charfct2[-1]:
                break

            err = false_off_new - false_off_old
            ll = ll + 1

        true_off[k] = charfct2[pick_on[k] + ll]    # The STA - LTA ratio value when crossing the threshold off 2nd time
        idx_off[k] = pick_on[k] + ll               # the index or position of the true off

    trigger_event = np.stack([pick_on, idx_off], 1)
    # ==================================================================================================================

    if trigger_event.shape[0] == 0:
        trg_on = []
        trg_off = []
        val_on = []
        val_off = []
        return trg_on, trg_on, val_on, trg_off, val_off

    elif trigger_event.shape[0] == 1:
        if trigger_event[0, 1] - trigger_event[0, 0] > int(300 * fs):
            trigger_event[0, 1] = trigger_event[0, 0] + int(300 * fs)

        trg_on = trigger_event[:, 0]
        trg_off = trigger_event[:, 1]
        val_on = charfct2[trg_on]
        val_off = charfct2[trg_off]
        return trg_on, val_on, trg_off, val_off

    # ==================================================================================================================
    # Merging Events That Have the Same Trigger Off Positions

    trig_on_0 = trigger_event[:, 0].copy()
    for j in range(trigger_event.shape[0] - 1):
        if abs(trigger_event[(j + 1), 1] - trigger_event[j, 1]) < 0.1:
            # trigger_event[(j + 1), 0] = -99999
            trig_on_0[(j + 1)] = -99999

    rm_idx = np.where(trig_on_0 == -99999)
    trigger_event = np.delete(trigger_event, rm_idx, axis=0)

    sz_0 = trigger_event.shape
    # ==================================================================================================================

    # ==================================================================================================================
    # Remove Events Shorter Than 5 Seconds

    for jj in range(sz_0[0]):
        if abs(trigger_event[jj, 1] - trigger_event[jj, 0]) < int(5 * fs):
            trigger_event[jj, 0] = -99999

    rm_idx_2 = np.where(trigger_event[:, 0] == -99999)
    trigger_event = np.delete(trigger_event, rm_idx_2, axis=0)
    # ==================================================================================================================

    # ==================================================================================================================
    # Adjusting Trigger offs That Overlap with the Subsequent Trigger ons

    sz_1 = trigger_event.shape
    for jj in range(sz_1[0]):
        if jj == sz_1[0] - 1:
            continue

        if trigger_event[jj, 1] == trigger_event[jj + 1, 0]:
            trigger_event[jj, 1] = trigger_event[jj, 1] - 1

    # ==================================================================================================================

    # ==================================================================================================================
    # Adjusting Trigger Offs by Checking the Envelope
    # Notes: length env_fct = length charfct --> consequences: the indexing is the same

    pre_noise_length = int(10 * fs) #Correspond to 10 seconds before trig_on points

    for kk in range(sz_1[0]):

        # Limit EQ Duration to 300 seconds
        if trigger_event[kk, 1] - trigger_event[kk, 0] > int(300* fs):
            trigger_event[kk, 1] = trigger_event[kk, 0] + int(300 * fs)
            continue

        # If the trig_on point is at the beginning of the array, proceed to the
        # next trig_on point (don't have the pre noise). Another protocol: if the
        # trig_off point is at the end of the array, proceed.

        if trigger_event[kk, 0] - pre_noise_length < 0 or trigger_event[kk, 1] == len(env_fct):
            continue

        # Use the median of the pre noise as a new threshold
        pre_noise_env_med = np.median(env_fct[(trigger_event[kk, 0] - pre_noise_length):(trigger_event[kk, 0] - 1)])

        # If the envelope value at trig_off is already below constant*median of pre
        # noise, leave it (keep the trig_off)

        if env_fct[trigger_event[kk, 1]] <= thresh_off_env * pre_noise_env_med:
            trigger_event[kk, 1] = trigger_event[kk, 1]
        else:
            status = env_fct[trigger_event[kk, 1]] > thresh_off_env * pre_noise_env_med

            while status:   # as long as the status is true do the while loop

                if trigger_event[kk, 1] - trigger_event[kk, 0] > int(300 * fs):
                    trigger_event[kk, 1] = trigger_event[kk, 0] + int(300 * fs)
                    break

                ll = trigger_event[kk, 1] + 1                              # move the trig_off point by one sample
                status = env_fct[ll] > thresh_off_env * pre_noise_env_med  # check whether it's above the treshold
                trigger_event[kk, 1] = ll

                if kk < sz_1[0] - 1:    # For events that are not the last detected event

                    if ll == trigger_event[(kk + 1), 0]: # If the searching arrives at the subsequent event
                        trigger_event[kk, 1] = ll - 1    # Move backward by one index
                        status = False                   # Stop searching

                    elif ll == len(env_fct):             # If the searching arrives at the end of the array
                        trigger_event[kk, 1] = ll
                        status = False                   # Stop searching

                else:                                    # For the last detected events
                    if ll == len(env_fct):               # If searching arrives at the end of the array
                        trigger_event[kk, 1] = ll
                        status = False                   # Stop searching

    sz_2 = trigger_event.shape
    count_rem = 1

    while count_rem < 50:
        for k in range(sz_2[0] - 1):
            if trigger_event[(k + 1), 0] < trigger_event[k, 1]:
                trigger_event[(k + 1), 0] = -99999
                if trigger_event[(k + 1), 1] > trigger_event[k, 1]:
                    trigger_event[k, 1] = trigger_event[(k + 1), 1]
                else:
                    trigger_event[k, 1] = trigger_event[k, 1]
        rm_idx_3 = np.where(trigger_event[:, 0] == -99999)
        trigger_event = np.delete(trigger_event, rm_idx_3, axis=0)
        sz_2 = trigger_event.shape
        count_rem = count_rem + 1

    trg_on = trigger_event[:, 0]
    trg_off = trigger_event[:, 1]
    # ==================================================================================================================

    # ==================================================================================================================
    # Looking For Minimum Envelope Between Each Trg_on and Trg_off

    for k in range(len(trg_on)):

        max_point = np.argmax(env_fct[trg_on[k]:(trg_off[k] + 1)])
        idx_max_point = trg_on[k] + int(max_point)
        evaluated_env = env_fct[idx_max_point:(trg_off[k] + 1)]
        pre_noise_env_med = np.median(env_fct[(trg_on[k] - pre_noise_length):(trg_on[k] - 1)])

        idx_first_env = np.where(evaluated_env <= thresh_off_env * pre_noise_env_med)[0]

        if idx_first_env.size == 0:
            idx_min_env = np.argmin(evaluated_env)
            trg_off[k] = idx_max_point + int(idx_min_env)
        else:
            trg_off[k] = idx_max_point + idx_first_env[0]

    trigger_event_f = np.stack([trg_on, trg_off], 1)

    # ==================================================================================================================

    # ==================================================================================================================
    # Remove Events Shorter than 5 Seconds

    for jj in range(len(trg_on)):
        if abs(trigger_event_f[jj, 1] - trigger_event_f[jj, 0]) < int(5 * fs):
            trigger_event_f[jj, 0] = -99999

    rm_idx_4 = np.where(trigger_event_f[:, 0] == -99999)
    trigger_event_f = np.delete(trigger_event_f, rm_idx_4, axis=0)

    trg_on_f = trigger_event_f[:, 0]
    trg_off_f = trigger_event_f[:, 1]
    val_on_f = charfct2[trg_on_f]
    val_off_f = charfct2[trg_off_f]
    # ==================================================================================================================

    return trg_on_f, val_on_f, trg_off_f, val_off_f, pick_on