/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.controls.controller

import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Binder
import android.os.Bundle
import android.os.IBinder
import android.os.RemoteException
import android.os.UserHandle
import android.service.controls.ControlsProviderService
import android.service.controls.ControlsProviderService.CALLBACK_BUNDLE
import android.service.controls.ControlsProviderService.CALLBACK_TOKEN
import android.service.controls.IControlsActionCallback
import android.service.controls.IControlsLoadCallback
import android.service.controls.IControlsProvider
import android.service.controls.IControlsSubscriber
import android.service.controls.IControlsSubscription
import android.service.controls.actions.ControlAction
import android.util.ArraySet
import android.util.Log
import com.android.internal.annotations.GuardedBy
import com.android.systemui.util.concurrency.DelayableExecutor
import java.util.concurrent.TimeUnit

/**
 * Manager for the lifecycle of the connection to a given [ControlsProviderService].
 *
 * This class handles binding and unbinding and requests to the service. The class will queue
 * requests until the service is connected and dispatch them then.
 *
 * @property context A SystemUI context for binding to the services
 * @property executor A delayable executor for posting timeouts
 * @property loadCallbackService a callback interface to hand the remote service for loading
 *                               controls
 * @property actionCallbackService a callback interface to hand the remote service for sending
 *                                 action responses
 * @property subscriberService an "subscriber" interface for requesting and accepting updates for
 *                             controls from the service.
 * @property user the user for whose this service should be bound.
 * @property componentName the name of the component for the service.
 */
class ControlsProviderLifecycleManager(
    private val context: Context,
    private val executor: DelayableExecutor,
    private val loadCallbackService: IControlsLoadCallback.Stub,
    private val actionCallbackService: IControlsActionCallback.Stub,
    private val subscriberService: IControlsSubscriber.Stub,
    val user: UserHandle,
    val componentName: ComponentName
) : IBinder.DeathRecipient {

    var lastLoadCallback: ControlsBindingController.LoadCallback? = null
        private set
    val token: IBinder = Binder()
    @GuardedBy("subscriptions")
    private val subscriptions = mutableListOf<IControlsSubscription>()
    private var requiresBound = false
    @GuardedBy("queuedMessages")
    private val queuedMessages: MutableSet<Message> = ArraySet()
    private var wrapper: ServiceWrapper? = null
    private var bindTryCount = 0
    private val TAG = javaClass.simpleName
    private var onLoadCanceller: Runnable? = null

    companion object {
        private const val MSG_LOAD = 0
        private const val MSG_SUBSCRIBE = 1
        private const val MSG_ACTION = 2
        private const val MSG_UNBIND = 3
        private const val BIND_RETRY_DELAY = 1000L // ms
        private const val LOAD_TIMEOUT_SECONDS = 30L // seconds
        private const val MAX_BIND_RETRIES = 5
        private const val MAX_CONTROLS_REQUEST = 100000L
        private const val DEBUG = true
        private val BIND_FLAGS = Context.BIND_AUTO_CREATE or Context.BIND_FOREGROUND_SERVICE or
                Context.BIND_WAIVE_PRIORITY
    }

    private val intent = Intent().apply {
        component = componentName
        putExtra(CALLBACK_BUNDLE, Bundle().apply {
            putBinder(CALLBACK_TOKEN, token)
        })
    }

    private fun bindService(bind: Boolean) {
        requiresBound = bind
        if (bind) {
            if (bindTryCount == MAX_BIND_RETRIES) {
                return
            }
            if (DEBUG) {
                Log.d(TAG, "Binding service $intent")
            }
            bindTryCount++
            try {
                context.bindServiceAsUser(intent, serviceConnection, BIND_FLAGS, user)
            } catch (e: SecurityException) {
                Log.e(TAG, "Failed to bind to service", e)
            }
        } else {
            if (DEBUG) {
                Log.d(TAG, "Unbinding service $intent")
            }
            bindTryCount = 0
            wrapper?.run {
                context.unbindService(serviceConnection)
            }
            wrapper = null
        }
    }

    private val serviceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            if (DEBUG) Log.d(TAG, "onServiceConnected $name")
            bindTryCount = 0
            wrapper = ServiceWrapper(IControlsProvider.Stub.asInterface(service))
            try {
                service.linkToDeath(this@ControlsProviderLifecycleManager, 0)
            } catch (_: RemoteException) {}
            handlePendingMessages()
        }

        override fun onServiceDisconnected(name: ComponentName?) {
            if (DEBUG) Log.d(TAG, "onServiceDisconnected $name")
            wrapper = null
            bindService(false)
        }
    }

    private fun handlePendingMessages() {
        val queue = synchronized(queuedMessages) {
            ArraySet(queuedMessages).also {
                queuedMessages.clear()
            }
        }
        if (Message.Unbind in queue) {
            bindService(false)
            return
        }
        if (Message.Load in queue) {
            load()
        }
        queue.filter { it is Message.Subscribe }.flatMap { (it as Message.Subscribe).list }.run {
            if (this.isNotEmpty()) {
                subscribe(this)
            }
        }
        queue.filter { it is Message.Action }.forEach {
            val msg = it as Message.Action
            action(msg.id, msg.action)
        }
    }

    override fun binderDied() {
        if (wrapper == null) return
        wrapper = null
        if (requiresBound) {
            if (DEBUG) {
                Log.d(TAG, "binderDied")
            }
            // Try rebinding some time later
        }
    }

    private fun queueMessage(message: Message) {
        synchronized(queuedMessages) {
            queuedMessages.add(message)
        }
    }

    private fun unqueueMessage(message: Message) {
        synchronized(queuedMessages) {
            queuedMessages.removeIf { it.type == message.type }
        }
    }

    private fun load() {
        if (DEBUG) {
            Log.d(TAG, "load $componentName")
        }
        if (!(wrapper?.load(loadCallbackService) ?: false)) {
            queueMessage(Message.Load)
            binderDied()
        }
    }

    private inline fun invokeOrQueue(f: () -> Unit, msg: Message) {
        wrapper?.run {
            f()
        } ?: run {
            queueMessage(msg)
            bindService(true)
        }
    }

    /**
     * Request a call to [ControlsProviderService.loadAvailableControls].
     *
     * If the service is not bound, the call will be queued and the service will be bound first.
     * The service will be bound after the controls are returned or the call times out.
     *
     * @param callback a callback in which to return the result back. If the call times out
     *                 [ControlsBindingController.LoadCallback.error] will be called instead.
     */
    fun maybeBindAndLoad(callback: ControlsBindingController.LoadCallback) {
        unqueueMessage(Message.Unbind)
        lastLoadCallback = callback
        onLoadCanceller = executor.executeDelayed({
            // Didn't receive a response in time, log and send back error
            Log.d(TAG, "Timeout waiting onLoad for $componentName")
            callback.error("Timeout waiting onLoad")
            // Don't accept load callbacks after this
            lastLoadCallback = null
            unbindService()
        }, LOAD_TIMEOUT_SECONDS, TimeUnit.SECONDS)

        invokeOrQueue(::load, Message.Load)
    }

    /**
     * Request a subscription to the [Publisher] returned by [ControlsProviderService.publisherFor]
     *
     * If the service is not bound, the call will be queued and the service will be bound first.
     *
     * @param controlIds a list of the ids of controls to send status back.
     */
    fun maybeBindAndSubscribe(controlIds: List<String>) {
        invokeOrQueue({ subscribe(controlIds) }, Message.Subscribe(controlIds))
    }

    private fun subscribe(controlIds: List<String>) {
        if (DEBUG) {
            Log.d(TAG, "subscribe $componentName - $controlIds")
        }
        if (!(wrapper?.subscribe(controlIds, subscriberService) ?: false)) {
            queueMessage(Message.Subscribe(controlIds))
            binderDied()
        }
    }

    /**
     * Request a call to [ControlsProviderService.performControlAction].
     *
     * If the service is not bound, the call will be queued and the service will be bound first.
     *
     * @param controlId the id of the [Control] the action is performed on
     * @param action the action performed
     */
    fun maybeBindAndSendAction(controlId: String, action: ControlAction) {
        invokeOrQueue({ action(controlId, action) }, Message.Action(controlId, action))
    }

    private fun action(controlId: String, action: ControlAction) {
        if (DEBUG) {
            Log.d(TAG, "onAction $componentName - $controlId")
        }
        if (!(wrapper?.action(controlId, action, actionCallbackService) ?: false)) {
            queueMessage(Message.Action(controlId, action))
            binderDied()
        }
    }

    /**
     * Starts the subscription to the [ControlsProviderService] and requests status of controls.
     *
     * @param subscription the subscriber to use to request controls
     * @see maybeBindAndLoad
     */
    fun startSubscription(subscription: IControlsSubscription) {
        synchronized(subscriptions) {
            subscriptions.add(subscription)
        }
        wrapper?.request(subscription, MAX_CONTROLS_REQUEST)
    }

    /**
     * Unsubscribe from this service, cancelling all status requests.
     */
    fun unsubscribe() {
        if (DEBUG) {
            Log.d(TAG, "unsubscribe $componentName")
        }
        unqueueMessage(Message.Subscribe(emptyList())) // Removes all subscribe messages

        val subs = synchronized(subscriptions) {
            ArrayList(subscriptions).also {
                subscriptions.clear()
            }
        }

        subs.forEach {
            wrapper?.cancel(it)
        }
    }

    /**
     * Request bind to the service.
     */
    fun bindService() {
        unqueueMessage(Message.Unbind)
        bindService(true)
    }

    /**
     * Request unbind from the service.
     */
    fun unbindService() {
        lastLoadCallback = null
        onLoadCanceller?.run()
        onLoadCanceller = null

        bindService(false)
    }

    override fun toString(): String {
        return StringBuilder("ControlsProviderLifecycleManager(").apply {
            append("component=$componentName")
            append(", user=$user")
            append(")")
        }.toString()
    }

    /**
     * Messages for the internal queue.
     */
    sealed class Message {
        abstract val type: Int
        object Load : Message() {
            override val type = MSG_LOAD
        }
        object Unbind : Message() {
            override val type = MSG_UNBIND
        }
        class Subscribe(val list: List<String>) : Message() {
            override val type = MSG_SUBSCRIBE
        }
        class Action(val id: String, val action: ControlAction) : Message() {
            override val type = MSG_ACTION
        }
    }
}
