use std::ops::Deref;

struct State<B>{
    b : B,
}

impl<B> State<B> {
    fn set(&mut self, b : B) {
        self.b = b
    }

    // fn trace<A, C>(&mut self, step : impl Fn(A, &B) -> (C, B)) -> impl FnMut(A) -> C {
    //     return |a| {
    //         let (c, b2) = step(a, &self.b);
    //         self.b = b2;
    //         return c;
    //     }
    // }

    // fn get(&self) -> B {
    //     let bb = self.b;
    //     return self.b;
    // }
}
struct StatefullFct<B, F>{
    b : B,
    f : F,
}

impl<B, F> StatefullFct<B, F> {
    fn truc<A, C>(&mut self, a : A) -> C where F : FnMut(A, &B) -> (C, B) {
        let (c, b) = (&mut self.f)(a, &self.b);
        self.b = b;
        return c;
    }
}

// fn trace<A, B, C>(step : impl Fn(A, B) -> (C, B), b : B) -> impl FnMut(A) -> C {
//     let mut bmut = b;
//     return move |a| {
//         let (c, b2) = step(a, bmut);
//         bmut = b2;
//         return c;
//     }
// }

// impl<B> State<B>{
//     fn get_fn<A, C>(&mut self, mut f : impl FnMut(A, B) -> (C, B)) -> impl FnMut(A) -> C {
//         return move |a| {
//             let plop : B = self.0;
//             let (c, b) = f(a, self.0);
//             self.0 = b;
//             return c;
//         }
//     }
// }

pub fn map_accum<A, B, C>(f : impl FnMut(A, &B) -> (C, B), b : B, ite : impl Iterator<Item = A>) -> impl Iterator<Item = C> {
    let mut sf = StatefullFct { b, f };
    let ff = move |a| {sf.truc(a)};
    let res = ite.map(ff);
    return res;
}

pub struct MapAccum<I, F, B>{
    ite : I,
    f : F,
    b : Option<B>
}

impl<I, F, B> MapAccum<I, F, B> {
    fn last_state(self) -> B {
        return self.b.unwrap();
    }
}

impl<A, C, I : Iterator<Item = A>, F : FnMut(A, B) -> (C, B), B> Iterator for MapAccum<I, F, B> {
    type Item = C;

    fn next(&mut self) -> Option<C> {
        self.ite.next().map(|a| {
            let old_state = self.b.take().unwrap();
            let (c, b) = (self.f)(a, old_state);
            self.b = Some(b);
            return c;
        })
    }
}

fn test() {
    let reference = Box::new(MapAccum {ite : 1, f : 2, b : Some(3)});
    let mut a = *reference;

}

pub trait SuperIterator : Iterator + Sized {
    // fn map_accum<B, C>(self, f : impl FnMut(Self::Item, &B) -> (C, B), b : B) -> Map<Self, fn(Self::Item) -> C> where Self : Sized{
    //     map_accum(f, b, self)
    // }

    // fn map_accum2<B, C>(self, f : impl FnMut(Self::Item, &B) -> (C, B), b : B) -> Map<Self, fn(Self::Item) -> C> where Self : Sized{
    //     let mut sf = StatefullFct { b, f };
    //     let res = self.map(move |a| {sf.truc(a)});
    //     return res;
    // }

    // fn map_accum2<B, C>(self, f : impl FnMut(Self::Item, &B) -> (C, B), b : B) -> impl Iterator<Item = C> {
    //     map_accum(f, b, self)
    // }

    fn map_accum<B, C, F : FnMut(Self::Item, B) -> (C, B)>(self, b : B, f : F) -> MapAccum<Self, F, B>{
        //panic!();
        MapAccum { ite : self, f, b : Some(b) }
    }

}

impl<T> SuperIterator for T where T : Iterator {}