mod transcriber;

use std::collections::{BTreeMap, HashSet};

use itertools::{EitherOrBoth, Itertools};
pub use transcriber::Transcriber;

use crate::choice_function::{self, ChoiceFunction};

#[derive(Clone, Debug)]
pub struct Genotype {
    pub chromosomes: BTreeMap<String, Chromosomes>,
}

type Chromosomes = (String, String);

pub trait Genetic: Default {
    fn transcribe(&mut self, t: Transcriber);
}

fn merge(choice_function: ChoiceFunction, one: &str, two: &str) -> String {
    let mut results = String::new();
    for pair in one.chars().zip_longest(two.chars()) {
        results.push(match pair {
            EitherOrBoth::Both(l, r) => *choice_function.choose(&[l, r]),
            EitherOrBoth::Left(l) => l,
            EitherOrBoth::Right(r) => r,
        });
    }
    results
}

impl Genotype {
    pub fn breed(&self, choice_function: ChoiceFunction, other: &Genotype) -> Genotype {
        let mut chromosomes: HashSet<String> = HashSet::new();
        chromosomes.extend(self.chromosomes.keys().cloned());
        chromosomes.extend(other.chromosomes.keys().cloned());

        let mut result: BTreeMap<String, Chromosomes> = BTreeMap::new();
        let placeholder = (String::new(), String::new());

        for k in chromosomes {
            let mine = self.chromosomes.get(&k).unwrap_or(&placeholder);
            let theirs = self.chromosomes.get(&k).unwrap_or(&placeholder);

            /*
            let mine_merged = merge(choice_function, &mine.0, &mine.1);
            let theirs_merged = merge(choice_function, &theirs.0, &theirs.1);
            result.insert(k, (mine_merged, theirs_merged));
            */
            let my_choice = (*choice_function.choose(&[&mine.0, &mine.1])).clone();
            let their_choice = (*choice_function.choose(&[&theirs.0, &theirs.1])).clone();
            result.insert(k, (my_choice, their_choice));
        }
        return Genotype {
            chromosomes: result,
        };
    }
}
