import re

# filters guides with:
#* More than 1 T/U in the last 4 nucleotides, which combine with the first few nucleotides of the gRNA scaffold to terminate Pol III transcription
#* More than 40% total T/U content
#* 4-mer T/U repeats
#* 5-mer mononucleotide repeats
#* Low-complexity sequences, defined as 10 nucleotides of 2-nt repeat, 12 nucleotides of 3- or 4-nt repeats, or 18 nucleotides of 5- or 6-nt repeats
#* <= 20% GC content
#* >= 90% GC content

def is_low_complexity(sequence, repeat_length, min_repeats):
    """
    Check if a sequence contains low-complexity regions.
    
    Args:
    sequence (str): The DNA sequence to check.
    repeat_length (int): The length of the repeat unit.
    min_repeats (int): The minimum number of repeats to consider as low complexity.
    
    Returns:
    bool: True if the sequence contains a low-complexity region, False otherwise.
    """
    pattern = f'(.{{{repeat_length}}})\\1{{{min_repeats-1},}}'
    return bool(re.search(pattern, sequence))

def is_valid_guide(sequence):
    # Convert to uppercase and replace U with T for uniformity
    seq = sequence.upper().replace('U', 'T')
    
    # Check for more than 1 T in the last 4 nucleotides
    if seq[-4:].count('T') > 1:
        return False
    
    # Check for more than 40% total T content
    if seq.count('T') / len(seq) > 0.4:
        return False
    
    # Check for 4-mer T repeats
    if 'TTTT' in seq:
        return False
    
    # Check for 5-mer mononucleotide repeats
    if any(base * 5 in seq for base in 'ATCG'):
        return False
    
    # Check for low-complexity sequences
    if (is_low_complexity(seq, 2, 5) or  # 10 nucleotides of 2-nt repeat (5 repeats)
        is_low_complexity(seq, 3, 4) or  # 12 nucleotides of 3-nt repeat (4 repeats)
        is_low_complexity(seq, 4, 3) or  # 12 nucleotides of 4-nt repeat (3 repeats)
        is_low_complexity(seq, 5, 3) or  # 15 nucleotides of 5-nt repeat (3 repeats)
        is_low_complexity(seq, 6, 3)):   # 18 nucleotides of 6-nt repeat (3 repeats)
        return False
    
    # Check GC content
    gc_content = (seq.count('G') + seq.count('C')) / len(seq)
    if gc_content <= 0.2 or gc_content >= 0.9:
        return False
    
    # If all checks pass, the guide is valid
    return True
