//
// Copyright (C) 2024 Automated Design Corp.. All Rights Reserved.
// Created Date: 2024-09-05 14:03:45
// -----
// Last Modified: 2024-09-05 16:08:10
// -----
//
//

use mechutil::actor::MechActor;
use std::sync::{Arc, Mutex};
use tokio::time::{Duration, sleep};

struct ActorStructExample {
    actor: MechActor,
    pub tick_count: Arc<Mutex<usize>>,
    pub async_count: Arc<tokio::sync::Mutex<usize>>,
}

impl ActorStructExample {
    pub fn new() -> Self {
        Self {
            actor: MechActor::new(std::time::Duration::from_millis(1000)),
            tick_count: Arc::new(Mutex::new(0)),
            async_count: Arc::new(tokio::sync::Mutex::new(0)),
        }
    }

    pub async fn start(&mut self) {
        let counter_1 = self.tick_count.clone();
        let _ = self
            .actor
            .register_tick(move || {
                let mut l = counter_1.lock().unwrap();
                *l += 1;
                println!("actor 2 tick 1 ");
            })
            .await;

        let counter_2 = self.tick_count.clone();
        let _ = self
            .actor
            .register_tick(move || {
                let mut l = counter_2.lock().unwrap();
                *l += 1;
                println!("actor 2 tick 2 ");
            })
            .await;

        let counter_3 = self.async_count.clone();
        if let Err(err) = self
            .actor
            .register_async_tick(move || {
                let async_counter = counter_3.clone();
                Box::pin(async move {
                    let mut l = async_counter.lock().await;
                    *l += 1;
                    println!("async actor 2 TICKING ASYNC, BABY!");
                })
            })
            .await
        {
            println!("Failed to register async tick: {}", err);
        }

        println!("SpawnTest registered tick callback");
    }

    pub async fn stop(&mut self) {
        let _ = self.actor.shutdown().await;
        println!("SpawnTest shutdown.");
    }
}

/// Integration test for the `MechActor` behavior
/// This test will simulate the actor's ticking functionality, both sync and async.
#[tokio::test]
async fn test_mech_actor() {
    let test_count = Arc::new(Mutex::new(0));

    // Initialize the main actor instance
    let handle = MechActor::new(Duration::from_millis(1000));

    // Initialize the test struct with an actor and start it
    let mut st = ActorStructExample::new();
    st.start().await;

    // Register additional ticks for the main actor
    let counter_1 = test_count.clone();
    let _ = handle
        .register_tick(move || {
            let mut l = counter_1.lock().unwrap();
            *l += 1;
            println!("actor 1 tick 1");
        })
        .await;

    // Stall the test for 3 seconds to allow tick events to fire
    sleep(Duration::from_millis(3000)).await;

    // Shut down the actor after ticks
    let _ = handle.shutdown().await;
    st.stop().await;

    println!("Test finished. Actors shut down.");

    // You can add assertions here to check any expected behavior, logs, or side effects
    // Example:
    // assert_eq!(/* some condition */, /* expected value */);

    {
        let l = test_count.lock().unwrap();
        assert!(*l != 0);
    }

    {
        let l = st.tick_count.lock().unwrap();
        assert!(*l != 0);
    }

    {
        let l = st.async_count.lock().await;
        assert!(*l != 0);
    }
}
