use std::time::Instant;
use theatre::prelude::*;

#[derive(Clone, Debug)]
struct Fibonacci(pub u32);

impl Message for Fibonacci {
    type Return = Result<u128, ()>;
}

struct FibonacciActor;

#[async_trait]
impl Actor for FibonacciActor {
    async fn starting(&mut self, _: &mut Context<Self>) {}
}

#[async_trait]
impl Handler<Fibonacci> for FibonacciActor {
    async fn handle(
        &mut self,
        msg: Fibonacci,
        _: &mut Context<Self>,
    ) -> <Fibonacci as Message>::Return {
        if msg.0 == 0 {
            Err(())
        } else if msg.0 == 1 {
            Ok(1)
        } else {
            let mut i = 0;
            let mut sum = 0;
            let mut last = 0;
            let mut curr = 1;
            while i < msg.0 - 1 {
                sum = last + curr;
                last = curr;
                curr = sum;
                i += 1;
            }
            Ok(sum)
        }
    }
}

#[tokio::main]
async fn main() {
    let now = Instant::now();

    let mut addr = FibonacciActor.spawn().await;

    // send 5 messages
    for _ in 0..100 {
        for n in 5..150 {
            addr.send(Fibonacci(n)).await.unwrap().unwrap();
        }
    }

    println!("{:?}", Instant::now().duration_since(now));
}
