package pl.novelpay.samplesdkcommunicator

import android.app.Application
import android.content.Context
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.launch
import pl.novelpay.app2app.model.state.IdleTransactionState
import pl.novelpay.client.core.Client
import pl.novelpay.client.core.configuration.PackageInfo
import pl.novelpay.client.core.configuration.SDKConfiguration
import pl.novelpay.client.sdk.ClientFactory
import pl.novelpay.client.sdk.communication.processor.ObservableEvent
import pl.novelpay.retailer.configuration.RetailerConfiguration
import pl.novelpay.transport.shared.message.DomainMessage
import pl.novelpay.util.logger.Logger

class Application : Application() {
  private val _interceptionScope = CoroutineScope(Dispatchers.IO)
  private val _interceptionChannel = MutableStateFlow<DomainMessage?>(null)
  val interceptionChannel: Flow<DomainMessage> = _interceptionChannel.filterNotNull()
  val sdk by lazy {
    ClientFactory.bindConfiguration(
      SDKConfiguration.defaultConfiguration(
        clientApplicationInfo = PackageInfo(
          applicationName = applicationInfo.name,
          applicationPackage = packageName
        ),
        paymentApplicationPackage = "com.marketpay.pos"
      )
    ).bindContext(
      context = applicationContext
    ).bindProtocolConfiguration(
      RetailerConfiguration(saleID = "Communicator_SALE")
    ).bindInterceptor(
      interceptor = { message ->
        _interceptionScope.launch { _interceptionChannel.emit(message) }
        Result.success(message)
      }
    ).bindEventObserver { event ->
      when (event) {
        is ObservableEvent.ServerEvent -> Logger.d("New server event")
        is ObservableEvent.TransactionStateChanged ->
          when (event.state) {
            is IdleTransactionState -> bringToForeground(MainActivity::class)
            else -> {
              // Ignore
            }
          }
      }
    }.build()
  }

  override fun onCreate() {
    sdk
    super.onCreate()
  }

  companion object {
    fun Context.getSDK(): Client = when (applicationContext) {
      is pl.novelpay.samplesdkcommunicator.Application -> {
        (applicationContext as pl.novelpay.samplesdkcommunicator.Application).sdk
      }

      else -> applicationContext.getSDK()
    }

    fun Context.interceptionChannel(): Flow<DomainMessage> = when (applicationContext) {
      is pl.novelpay.samplesdkcommunicator.Application -> {
        (applicationContext as pl.novelpay.samplesdkcommunicator.Application).interceptionChannel
      }

      else -> applicationContext.interceptionChannel()
    }
  }
}