@startuml Actor Termination
title Actor Termination (stop, kill, and lifecycle completion)

actor Client
participant "ActorRef<T>" as ActorRef_obj
participant "MailboxChannel (mpsc)" as MailboxChannel
participant "TerminateChannel (mpsc)" as TerminateChannel
participant "run_actor_lifecycle()" as Lifecycle
participant "Actor::on_run()" as on_run_method
participant "Actor::on_stop()" as on_stop_method
participant "JoinHandle" as JoinHandle_obj

box "Actor Task" #LightCoral
    participant Lifecycle
    participant on_run_method
    participant on_stop_method
end box

== Normal Operation ==
Lifecycle -> Lifecycle: Main tokio::select! loop (biased)
activate Lifecycle
loop Idle Processing (when message queue empty)
  Lifecycle -> on_run_method: Calls actor.on_run(&actor_weak).await
  activate on_run_method
  on_run_method --> Lifecycle: Returns Ok(true), Ok(false), or Err(error)
  deactivate on_run_method
  note right of Lifecycle: Ok(true): continue idle processing\nOk(false): disable idle processing\nErr(): terminate with failure
end

== Stop Operation (Graceful) ==
Client -> ActorRef_obj: actor_ref.stop().await
activate ActorRef_obj
ActorRef_obj -> MailboxChannel: sender.send(MailboxMessage::StopGracefully(actor_ref)).await
deactivate ActorRef_obj

MailboxChannel -> Lifecycle: tokio::select! receives StopGracefully
Lifecycle -> on_stop_method: Calls actor.on_stop(&actor_weak, killed = false).await
activate on_stop_method
on_stop_method --> Lifecycle: Returns Ok(()) or Err(error)
deactivate on_stop_method

alt on_stop Success
  Lifecycle -> Lifecycle: Breaks message loop gracefully
  Lifecycle -> MailboxChannel: receiver.close()
  Lifecycle -> TerminateChannel: terminate_receiver.close()
  Lifecycle --> JoinHandle_obj: ActorResult::Completed { actor, killed: false }
else on_stop Failure
  Lifecycle --> JoinHandle_obj: ActorResult::Failed { phase: OnStop, killed: false, .. }
end
deactivate Lifecycle

== Kill Operation (Immediate) ==
Client -> ActorRef_obj: actor_ref.kill()
activate ActorRef_obj
ActorRef_obj -> TerminateChannel: terminate_sender.try_send(ControlSignal::Terminate)
deactivate ActorRef_obj

TerminateChannel -> Lifecycle: tokio::select! (biased) receives Terminate signal
activate Lifecycle
Lifecycle -> on_stop_method: Calls actor.on_stop(&actor_weak, killed = true).await
activate on_stop_method
on_stop_method --> Lifecycle: Returns Ok(()) or Err(error)
deactivate on_stop_method

alt on_stop Success
  Lifecycle -> Lifecycle: Breaks message loop immediately
  Lifecycle -> MailboxChannel: receiver.close()
  Lifecycle -> TerminateChannel: terminate_receiver.close()
  Lifecycle --> JoinHandle_obj: ActorResult::Completed { actor, killed: true }
else on_stop Failure
  Lifecycle --> JoinHandle_obj: ActorResult::Failed { phase: OnStop, killed: true, .. }
end
deactivate Lifecycle

== Termination via on_run Error ==
note over Lifecycle, on_stop_method
  When on_run returns an error, on_stop IS called for cleanup.
  The actor then terminates with ActorResult::Failed.
end note

Lifecycle -> on_run_method: Calls actor.on_run(&actor_weak).await
activate Lifecycle
activate on_run_method
on_run_method --> Lifecycle: Returns Err(error)
deactivate on_run_method

Lifecycle -> on_stop_method: Calls on_stop(&actor_weak, killed) for cleanup
activate on_stop_method
on_stop_method --> Lifecycle: Returns (result logged if error)
deactivate on_stop_method

Lifecycle --> JoinHandle_obj: ActorResult::Failed { phase: OnRun, actor: Some(actor), error, killed }
deactivate Lifecycle

== All ActorRef Instances Dropped ==
note over ActorRef_obj: All strong references dropped
MailboxChannel -> Lifecycle: receiver.recv() returns None (channel closed)
activate Lifecycle
Lifecycle -> on_stop_method: Calls actor.on_stop(&actor_weak, killed = false).await
activate on_stop_method
on_stop_method --> Lifecycle: Returns Ok(()) or Err(error)
deactivate on_stop_method
Lifecycle -> Lifecycle: Natural termination due to no references
Lifecycle --> JoinHandle_obj: ActorResult::Completed { actor, killed: false }
deactivate Lifecycle

@enduml