/*
 * Copyright (C) 2025 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.google.snippet.telecom;

import android.os.Bundle;
import android.os.IBinder;
import android.content.Intent;
import android.telecom.Connection;
import android.telecom.ConnectionRequest;
import android.telecom.ConnectionService;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import com.google.android.mobly.snippet.util.Log;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/** Self-managed ConnectionService implementation for Mobly Snippet. */
public class SelfManagedConnectionService extends ConnectionService {
  static final int TIMEOUT_MILLIS = 10000;

  final Object mConnectionsLock = new Object();

  List<ConnectionImpl> mConnections = new ArrayList<>();
  CountDownLatch mConnectionLatch = new CountDownLatch(1);

  private ConnectionImpl.Listener mConnectionListener =
      new ConnectionImpl.Listener() {
        @Override
        void onDestroyed(ConnectionImpl connection) {
          Log.i("onDestroyed: " + connection);
          synchronized (mConnectionsLock) {
            mConnections.remove(connection);
          }
        }
      };

  private static SelfManagedConnectionService mConnectionService;
  private static CountDownLatch mBindingLatch = new CountDownLatch(1);

  public static SelfManagedConnectionService getConnectionService() {
    return mConnectionService;
  }

  public static SelfManagedConnectionService waitForAndGetConnectionService() {
    if (mConnectionService == null) {
      try {
        mBindingLatch.await(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
      } catch (InterruptedException e) {
        Log.w("binding is interrupted");
      }
    }
    return mConnectionService;
  }

  public List<ConnectionImpl> getConnections() {
    synchronized (mConnectionsLock) {
      return new ArrayList<ConnectionImpl>(mConnections);
    }
  }

  public ConnectionImpl waitForAndGetConnection() {
    try {
      mConnectionLatch.await(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
    } catch (InterruptedException e) {
      Log.w("getting connection is interrupted");
    }
    mConnectionLatch = new CountDownLatch(1);
    synchronized (mConnectionsLock) {
      if (!mConnections.isEmpty()) {
        return mConnections.get(0);
      } else {
        return null;
      }
    }
  }

  public void onBindClient(Intent intent) {
    mConnectionService = this;
    if (mBindingLatch != null) {
      mBindingLatch.countDown();
    }
    mBindingLatch = new CountDownLatch(1);
  }

  @Override
  public boolean onUnbind(Intent intent) {
    Log.i("onUnbind: " + intent);
    mConnectionService = null;
    return super.onUnbind(intent);
  }

  @Override
  public Connection onCreateIncomingConnection(
      PhoneAccountHandle connectionManagerPhoneAccount, ConnectionRequest request) {
    Log.i("onCreateIncomingConnection: " + connectionManagerPhoneAccount + ", " + request);
    return createConnection(request, true /* isIncoming */);
  }

  @Override
  public Connection onCreateOutgoingConnection(
      PhoneAccountHandle connectionManagerAccount, ConnectionRequest request) {
    Log.i("onCreateOutgoingConnection: " + connectionManagerAccount + ", " + request);
    return createConnection(request, false /* isIncoming */);
  }

  private Connection createConnection(ConnectionRequest request, boolean isIncoming) {
    boolean useAudioClip =
        request.getExtras().getBoolean(ConnectionImpl.EXTRA_PLAY_CS_AUDIO, false);
    ConnectionImpl connection =
        new ConnectionImpl(getApplicationContext(), isIncoming, mConnectionListener, useAudioClip);
    connection.setConnectionCapabilities(
        Connection.CAPABILITY_SUPPORT_HOLD | Connection.CAPABILITY_HOLD);
    connection.setConnectionProperties(Connection.PROPERTY_SELF_MANAGED);
    connection.setAddress(request.getAddress(), TelecomManager.PRESENTATION_ALLOWED);
    connection.setExtras(request.getExtras());

    Bundle moreExtras = new Bundle();
    moreExtras.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE, request.getAccountHandle());
    connection.putExtras(moreExtras);
    connection.setVideoState(request.getVideoState());

    synchronized (mConnectionsLock) {
      mConnections.add(connection);
    }
    if (mConnectionLatch != null) {
      mConnectionLatch.countDown();
    }
    return connection;
  }
}

