use crate::{
    alloc_generators::{CollectionGenerator, DEFAULT_LEN_RANGE},
    Driver, TypeGenerator, TypeGeneratorWithParams, TypeValueGenerator, ValueGenerator,
};
use alloc::string::String;
use core::ops::RangeInclusive;
pub struct StringGenerator<C, L> {
    chars: C,
    len: L,
}
impl<C, L> StringGenerator<C, L> {
    pub fn chars<Gen: ValueGenerator<Output = char>>(self, chars: Gen) -> StringGenerator<Gen, L> {
        StringGenerator {
            chars,
            len: self.len,
        }
    }
    pub fn map_chars<Gen: ValueGenerator<Output = char>, F: Fn(C) -> Gen>(
        self,
        map: F,
    ) -> StringGenerator<Gen, L> {
        StringGenerator {
            chars: map(self.chars),
            len: self.len,
        }
    }
    pub fn len<Gen: ValueGenerator<Output = Len>, Len: Into<usize>>(
        self,
        len: Gen,
    ) -> StringGenerator<C, Gen> {
        StringGenerator {
            chars: self.chars,
            len,
        }
    }
    pub fn map_len<Gen: ValueGenerator<Output = Len>, F: Fn(L) -> Gen, Len: Into<usize>>(
        self,
        map: F,
    ) -> StringGenerator<C, Gen> {
        StringGenerator {
            chars: self.chars,
            len: map(self.len),
        }
    }
}
impl<G: ValueGenerator<Output = char>, L: ValueGenerator<Output = Len>, Len: Into<usize>>
    ValueGenerator for StringGenerator<G, L>
{
    type Output = String;
    fn generate<D: Driver>(&self, driver: &mut D) -> Option<Self::Output> {
        let len = ValueGenerator::generate(&self.len, driver)?.into();
        Iterator::map(0..len, |_| ValueGenerator::generate(&self.chars, driver)).collect()
    }
    fn mutate<D: Driver>(&self, driver: &mut D, value: &mut Self::Output) -> Option<()> {
        let len = ValueGenerator::generate(&self.len, driver)?.into();
        CollectionGenerator::mutate_collection(value, driver, len, &self.chars)
    }
}
impl CollectionGenerator for String {
    type Item = char;
    fn mutate_collection<D: Driver, G>(
        &mut self,
        driver: &mut D,
        new_len: usize,
        item_gen: &G,
    ) -> Option<()>
    where
        G: ValueGenerator<Output = Self::Item>,
    {
        let prev = core::mem::take(self);
        let to_mutate = self.len().min(new_len);
        let to_append = new_len.saturating_sub(to_mutate);
        for mut c in prev.chars().take(to_mutate) {
            item_gen.mutate(driver, &mut c)?;
            self.push(c);
        }
        for _ in 0..to_append {
            self.push(item_gen.generate(driver)?);
        }
        #[cfg(test)]
        assert_eq!(self.chars().count(), new_len);
        Some(())
    }
}
impl TypeGenerator for String {
    fn generate<D: Driver>(driver: &mut D) -> Option<Self> {
        String::gen_with().generate(driver)
    }
}
impl TypeGeneratorWithParams for String {
    type Output = StringGenerator<TypeValueGenerator<char>, RangeInclusive<usize>>;
    fn gen_with() -> Self::Output {
        StringGenerator {
            chars: Default::default(),
            len: DEFAULT_LEN_RANGE,
        }
    }
}
impl ValueGenerator for String {
    type Output = Self;
    fn generate<D: Driver>(&self, _driver: &mut D) -> Option<Self> {
        Some(self.clone())
    }
}
#[test]
fn string_type_test() {
    let _ = generator_test!(gen::<String>());
}
#[test]
fn string_with_test() {
    for _ in 0..100 {
        if let Some(string) = generator_test!(gen::<String>().with().len(32usize)) {
            assert_eq!(string.chars().count(), 32usize);
            return;
        }
    }
    panic!("failed to generate a valid string");
}