package com.rosetta.messenger.network

import com.rosetta.messenger.network.connection.BootstrapCoordinator
import com.rosetta.messenger.network.connection.OwnProfileFallbackTimerService
import com.rosetta.messenger.network.connection.ProtocolLifecycleStateStoreImpl
import com.rosetta.messenger.network.connection.RuntimeLifecycleStateMachine
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow

internal class RuntimeStateAssembly(
    scope: CoroutineScope,
    readyPacketQueueMax: Int,
    readyPacketQueueTtlMs: Long,
    ownProfileFallbackTimeoutMs: Long,
    addLog: (String) -> Unit,
    shortKeyForLog: (String) -> String,
    sendPacketDirect: (Packet) -> Unit,
    onOwnProfileFallbackTimeout: (Long) -> Unit,
    clearLastSubscribedTokenValue: () -> Unit
) {
    private val readyPacketGate =
        ReadyPacketGate(
            maxSize = readyPacketQueueMax,
            ttlMs = readyPacketQueueTtlMs
        )

    val bootstrapCoordinator =
        BootstrapCoordinator(
            readyPacketGate = readyPacketGate,
            addLog = addLog,
            shortKeyForLog = shortKeyForLog,
            sendPacketDirect = sendPacketDirect
        )

    val lifecycleStateMachine =
        RuntimeLifecycleStateMachine(
            bootstrapCoordinator = bootstrapCoordinator,
            addLog = addLog
        )

    private val ownProfileFallbackTimerService =
        OwnProfileFallbackTimerService(
            scope = scope,
            fallbackTimeoutMs = ownProfileFallbackTimeoutMs,
            onTimeout = onOwnProfileFallbackTimeout
        )

    val lifecycleStateStore =
        ProtocolLifecycleStateStoreImpl(
            lifecycleStateMachine = lifecycleStateMachine,
            ownProfileFallbackTimerService = ownProfileFallbackTimerService,
            clearLastSubscribedTokenValue = clearLastSubscribedTokenValue
        )

    val connectionLifecycleState: StateFlow<ConnectionLifecycleState> =
        lifecycleStateMachine.connectionLifecycleState

    fun recomputeConnectionLifecycleState(reason: String) {
        lifecycleStateMachine.recompute(reason)
    }
}
