
"""PKTron Biology — Genetic Algorithms & Mutation Simulation."""
import numpy as np

def random_genome(length, alphabet=("A","T","C","G"), seed=None):
    rng = np.random.default_rng(seed)
    return "".join(rng.choice(list(alphabet), size=length))


def crossover(parent1, parent2, n_points=1, seed=None):
    """
    N-point crossover between two equal-length string genomes.
    Returns (child1, child2).
    """
    n   = len(parent1)
    rng = np.random.default_rng(seed)
    pts = sorted(rng.choice(range(1,n), size=n_points, replace=False))
    pts = [0]+list(pts)+[n]
    c1, c2 = [], []
    for k in range(len(pts)-1):
        seg = slice(pts[k],pts[k+1])
        if k%2==0: c1.append(parent1[seg]); c2.append(parent2[seg])
        else:       c1.append(parent2[seg]); c2.append(parent1[seg])
    return "".join(c1), "".join(c2)


def point_mutation(genome, rate=0.01, alphabet=("A","T","C","G"), seed=None):
    """Mutate genome with given per-site probability."""
    rng = np.random.default_rng(seed)
    g   = list(genome)
    for i in range(len(g)):
        if rng.random() < rate:
            alts = [b for b in alphabet if b!=g[i]]
            g[i] = str(rng.choice(alts))
    return "".join(g)


def insertion_mutation(genome, rate=0.005, alphabet=("A","T","C","G"), seed=None):
    rng = np.random.default_rng(seed)
    out = []
    for base in genome:
        out.append(base)
        if rng.random() < rate:
            out.append(str(rng.choice(list(alphabet))))
    return "".join(out)


def deletion_mutation(genome, rate=0.005, seed=None):
    rng = np.random.default_rng(seed)
    return "".join(b for b in genome if rng.random() >= rate)


def fitness_gc_target(genome, target_gc=0.5):
    """Fitness = 1 - |GC - target|"""
    gc = (genome.count("G")+genome.count("C"))/max(1,len(genome))
    return 1 - abs(gc - target_gc)
