/*
 * Copyright (C) 2021 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 androidx.health.services.client.impl.ipc.internal;

import static com.google.common.base.Preconditions.checkNotNull;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.os.DeadObjectException;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import androidx.annotation.Nullable;
import androidx.annotation.RestrictTo;
import androidx.annotation.RestrictTo.Scope;
import androidx.annotation.VisibleForTesting;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentLinkedQueue;

import javax.annotation.concurrent.NotThreadSafe;

/**
 * A class that maintains a connection to IPC backend service. If connection is not available it
 * uses a queue to store service requests until connection is renewed. One {@link ServiceConnection}
 * is associated with one AIDL file .
 *
 * <p>Note: this class is not thread safe and should be called always from the same thread.
 *
 */
@NotThreadSafe
@RestrictTo(Scope.LIBRARY)
public class ServiceConnection implements android.content.ServiceConnection {
    private static final String TAG = "ServiceConnection";

    /** Callback for reporting back to the manager. */
    public interface Callback {

        /** Called when the connection to the server was successfully established. */
        void onConnected(ServiceConnection connection);

        /**
         * Called when the connection to the server was lost.
         *
         * @param connection Represents this connection to a service.
         * @param reconnectDelayMs Delay before the caller should try to reconnect this connection.
         */
        void onDisconnected(ServiceConnection connection, long reconnectDelayMs);

        /**
         * Return true if the {@link ServiceConnection} should bind to the service in the same
         * application for testing reason.
         */
        boolean isBindToSelfEnabled();
    }

    private static final int MAX_RETRIES = 10;

    private final Context mContext;
    private final Queue<QueueOperation> mOperationQueue = new ConcurrentLinkedQueue<>();
    private final ConnectionConfiguration mConnectionConfiguration;
    private final ExecutionTracker mExecutionTracker;
    private final Map<ListenerKey, QueueOperation> mRegisteredListeners = new HashMap<>();
    private final Callback mCallback;

    @VisibleForTesting @Nullable IBinder mBinder;
    private volatile boolean mIsServiceBound;
    /** Denotes how many times connection to the service failed and we retried. */
    private int mServiceConnectionRetry;

    ServiceConnection(
            Context context,
            ConnectionConfiguration connectionConfiguration,
            ExecutionTracker executionTracker,
            Callback callback) {
        this.mContext = checkNotNull(context);
        this.mConnectionConfiguration = checkNotNull(connectionConfiguration);
        this.mExecutionTracker = checkNotNull(executionTracker);
        this.mCallback = checkNotNull(callback);
    }

    private String getBindPackageName() {
        if (mCallback.isBindToSelfEnabled()) {
            return mContext.getPackageName();
        } else {
            return mConnectionConfiguration.getPackageName();
        }
    }

    /** Connects to the service. */
    public void connect() {
        if (mIsServiceBound) {
            return;
        }
        try {
            mIsServiceBound =
                    mContext.bindService(
                            new Intent()
                                    .setPackage(getBindPackageName())
                                    .setAction(mConnectionConfiguration.getBindAction()),
                            this,
                            Context.BIND_AUTO_CREATE | Context.BIND_ADJUST_WITH_ACTIVITY);
        } catch (SecurityException exception) {
            Log.w(
                    TAG,
                    "Failed to bind connection '"
                            + mConnectionConfiguration.getKey()
                            + "', no permission or service not found.",
                    exception);
            mIsServiceBound = false;
            mBinder = null;
            throw exception;
        }

        if (!mIsServiceBound) {
            // Service not found or we don't have permission to call it.
            Log.e(
                    TAG,
                    "Connection to service is not available for package '"
                            + mConnectionConfiguration.getPackageName()
                            + "' and action '"
                            + mConnectionConfiguration.getBindAction()
                            + "'.");
            handleNonRetriableDisconnection(new CancellationException("Service not available"));
        }
    }

    private void handleNonRetriableDisconnection(Throwable throwable) {
        // Set retry count to maximum to prevent retries
        mServiceConnectionRetry = MAX_RETRIES;
        handleRetriableDisconnection(throwable);
    }

    private synchronized void handleRetriableDisconnection(Throwable throwable) {
        if (isConnected()) {
            // Connection is already re-established. So just return.
            Log.w(TAG, "Connection is already re-established. No need to reconnect again");
            return;
        }

        clearConnection(throwable);

        if (mServiceConnectionRetry < MAX_RETRIES) {
            Log.w(
                    TAG,
                    "WCS SDK Client '"
                            + mConnectionConfiguration.getClientName()
                            + "' disconnected, retrying connection. Retry attempt: "
                            + mServiceConnectionRetry,
                    throwable);
            mCallback.onDisconnected(this, getRetryDelayMs(mServiceConnectionRetry));
        } else {
            Log.e(TAG, "Connection disconnected and maximum number of retries reached.", throwable);
        }
    }

    private static int getRetryDelayMs(int retryNumber) {
        // Exponential retry delay starting on 200ms.
        return (200 << retryNumber);
    }

    @VisibleForTesting
    void clearConnection(Throwable throwable) {
        if (mIsServiceBound) {
            try {
                mContext.unbindService(this);
                mIsServiceBound = false;
            } catch (IllegalArgumentException e) {
                Log.e(TAG, "Failed to unbind the service. Ignoring and continuing", e);
            }
        }

        mBinder = null;
        mExecutionTracker.cancelPendingFutures(throwable);
        cancelAllOperationsInQueue(throwable);
    }

    void enqueue(QueueOperation operation) {
        if (isConnected()) {
            execute(operation);
        } else {
            mOperationQueue.add(operation);
            connect();
        }
    }

    void registerListener(ListenerKey listenerKey, QueueOperation registerListenerOperation) {
        mRegisteredListeners.put(listenerKey, registerListenerOperation);
        if (isConnected()) {
            enqueue(registerListenerOperation);
        } else {
            connect();
        }
    }

    void unregisterListener(ListenerKey listenerKey, QueueOperation unregisterListenerOperation) {
        mRegisteredListeners.remove(listenerKey);
        enqueue(unregisterListenerOperation);
    }

    void maybeReconnect() {
        if (mRegisteredListeners.isEmpty()) {
            Log.d(
                    TAG,
                    "No listeners registered, service "
                            + mConnectionConfiguration.getClientName()
                            + " is not automatically reconnected.");
        } else {
            mServiceConnectionRetry++;
            Log.d(
                    TAG,
                    "Listeners for service "
                            + mConnectionConfiguration.getClientName()
                            + " are registered, reconnecting.");
            connect();
        }
    }

    @VisibleForTesting
    void execute(QueueOperation operation) {
        try {
            operation.trackExecution(mExecutionTracker);
            operation.execute(checkNotNull(mBinder));
        } catch (DeadObjectException exception) {
            handleRetriableDisconnection(exception);
            // TODO(b/152024821): Consider possible TransactionTooLargeException failure.
        } catch (RemoteException | RuntimeException exception) {
            operation.setException(exception);
        }
    }

    void reRegisterAllListeners() {
        for (Map.Entry<ListenerKey, QueueOperation> entry : mRegisteredListeners.entrySet()) {
            Log.d(TAG, "Re-registering listener: " + entry.getKey());
            execute(entry.getValue());
        }
    }

    void refreshServiceVersion() {
        mOperationQueue.add(mConnectionConfiguration.getRefreshVersionOperation());
    }

    void flushQueue() {
        for (QueueOperation operation : new ArrayList<>(mOperationQueue)) {
            boolean removed = mOperationQueue.remove(operation);
            if (removed) {
                execute(operation);
            }
        }
    }

    private void cancelAllOperationsInQueue(Throwable throwable) {
        for (QueueOperation operation : new ArrayList<>(mOperationQueue)) {
            boolean removed = mOperationQueue.remove(operation);
            if (removed) {
                operation.setException(throwable);
                execute(operation);
            }
        }
    }

    private boolean isConnected() {
        return mBinder != null && mBinder.isBinderAlive();
    }

    @Override
    public void onServiceConnected(ComponentName componentName, IBinder binder) {
        Log.d(TAG, "onServiceConnected(), componentName = " + componentName);
        if (binder == null) {
            Log.e(TAG, "Service connected but binder is null.");
            return;
        }
        mServiceConnectionRetry = 0;
        cleanOnDeath(binder);
        this.mBinder = binder;
        mCallback.onConnected(this);
    }

    private void cleanOnDeath(IBinder binder) {
        try {
            binder.linkToDeath(
                    () -> {
                        Log.w(
                                TAG,
                                "Binder died for client:"
                                        + mConnectionConfiguration.getClientName());
                        handleRetriableDisconnection(new CancellationException());
                    },
                    /* flags= */ 0);
        } catch (RemoteException exception) {
            Log.w(
                    TAG,
                    "Cannot link to death, binder already died. Cleaning operations.",
                    exception);
            handleRetriableDisconnection(exception);
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName componentName) {
        Log.d(TAG, "onServiceDisconnected(), componentName = " + componentName);
        // Service disconnected but binding still exists so it should reconnect automatically.
    }

    @Override
    public void onBindingDied(ComponentName name) {
        Log.e(TAG, "Binding died for client '" + mConnectionConfiguration.getClientName() + "'.");
        handleRetriableDisconnection(new CancellationException());
    }

    @Override
    public void onNullBinding(ComponentName name) {
        Log.e(
                TAG,
                "Cannot bind client '"
                        + mConnectionConfiguration.getClientName()
                        + "', binder is null");
        // This connection will never be usable, don't bother with retries.
        handleRetriableDisconnection(new CancellationException("Null binding"));
    }
}
