/*
 * Copyright (C) 2018 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.settings.network.telephony;

import static android.app.slice.Slice.EXTRA_TOGGLE_STATE;

import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME;

import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionManager;
import android.telephony.ims.ImsMmTelManager;
import android.util.Log;

import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.drawable.IconCompat;
import androidx.slice.Slice;
import androidx.slice.builders.ListBuilder;
import androidx.slice.builders.ListBuilder.RowBuilder;
import androidx.slice.builders.SliceAction;

import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.network.ims.VolteQueryImsState;
import com.android.settings.slices.CustomSliceRegistry;
import com.android.settings.slices.SliceBroadcastReceiver;

/**
 * Helper class to control slices for enhanced 4g LTE settings.
 */
public class Enhanced4gLteSliceHelper {

    private static final String TAG = "Enhanced4gLteSlice";

    /**
     * Action passed for changes to enhanced 4g LTE slice (toggle).
     */
    public static final String ACTION_ENHANCED_4G_LTE_CHANGED =
            "com.android.settings.mobilenetwork.action.ENHANCED_4G_LTE_CHANGED";

    /**
     * Action for mobile network settings activity which
     * allows setting configuration for Enhanced 4G LTE
     * related settings
     */
    public static final String ACTION_MOBILE_NETWORK_SETTINGS_ACTIVITY =
            "android.settings.NETWORK_OPERATOR_SETTINGS";

    private final Context mContext;

    /**
     * Phone package name
     */
    private static final String PACKAGE_PHONE = "com.android.phone";

    /**
     * String resource type
     */
    private static final String RESOURCE_TYPE_STRING = "string";

    /**
     * Enhanced 4g lte mode title variant resource name
     */
    private static final String RESOURCE_ENHANCED_4G_LTE_MODE_TITLE_VARIANT =
            "enhanced_4g_lte_mode_title_variant";

    private static final int MODE_VOLTE = 0;
    private static final int MODE_ADVANCED_CALL = 1;
    private static final int MODE_4G_CALLING = 2;

    @VisibleForTesting
    public Enhanced4gLteSliceHelper(Context context) {
        mContext = context;
    }

    /**
     * Returns Slice object for enhanced_4g_lte settings.
     *
     * If enhanced 4g LTE is not supported for the current carrier, this method will return slice
     * with not supported message.
     *
     * If enhanced 4g LTE is not editable for the current carrier, this method will return slice
     * with not editable message.
     *
     * If enhanced 4g LTE setting can be changed, this method will return the slice to toggle
     * enhanced 4g LTE option with ACTION_ENHANCED_4G_LTE_CHANGED as endItem.
     */
    public Slice createEnhanced4gLteSlice(Uri sliceUri) {
        final int subId = getDefaultVoiceSubId();

        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
            Log.d(TAG, "Invalid subscription Id");
            return null;
        }

        if (isCarrierConfigManagerKeyEnabled(
                CarrierConfigManager.KEY_HIDE_ENHANCED_4G_LTE_BOOL, subId, false)
                || !isCarrierConfigManagerKeyEnabled(
                CarrierConfigManager.KEY_EDITABLE_ENHANCED_4G_LTE_BOOL, subId,
                true)) {
            Log.d(TAG, "Setting is either hidden or not editable");
            return null;
        }

        final VolteQueryImsState queryState = queryImsState(subId);
        if (!queryState.isVoLteProvisioned()) {
            Log.d(TAG, "Setting is either not provisioned or not enabled by Platform");
            return null;
        }

        try {
            return getEnhanced4gLteSlice(sliceUri,
                    queryState.isEnabledByUser(), subId);
        } catch (IllegalArgumentException e) {
            Log.e(TAG, "Unable to read the current Enhanced 4g LTE status", e);
            return null;
        }
    }

    /**
     * Builds a toggle slice where the intent takes you to the Enhanced 4G LTE page and the toggle
     * enables/disables Enhanced 4G LTE mode setting.
     */
    private Slice getEnhanced4gLteSlice(Uri sliceUri, boolean isEnhanced4gLteEnabled, int subId) {
        final IconCompat icon = IconCompat.createWithResource(mContext,
                R.drawable.ic_launcher_settings);

        return new ListBuilder(mContext, sliceUri, ListBuilder.INFINITY)
                .setAccentColor(Utils.getColorAccentDefaultColor(mContext))
                .addRow(new RowBuilder()
                        .setTitle(getEnhanced4glteModeTitle(subId))
                        .addEndItem(
                                SliceAction.createToggle(
                                        getBroadcastIntent(ACTION_ENHANCED_4G_LTE_CHANGED),
                                        null /* actionTitle */, isEnhanced4gLteEnabled))
                        .setPrimaryAction(
                                SliceAction.createDeeplink(
                                        getActivityIntent(ACTION_MOBILE_NETWORK_SETTINGS_ACTIVITY),
                                        icon,
                                        ListBuilder.ICON_IMAGE,
                                        getEnhanced4glteModeTitle(subId))))
                .build();
    }

    /**
     * Handles Enhanced 4G LTE mode setting change from Enhanced 4G LTE slice and posts
     * notification. Should be called when intent action is ACTION_ENHANCED_4G_LTE_CHANGED
     *
     * @param intent action performed
     */
    public void handleEnhanced4gLteChanged(Intent intent) {
        // skip checking when no toggle state update contained within Intent
        final boolean newValue = intent.getBooleanExtra(EXTRA_TOGGLE_STATE, false);
        if (newValue != intent.getBooleanExtra(EXTRA_TOGGLE_STATE, true)) {
            notifyEnhanced4gLteUpdate();
            return;
        }

        final int subId = getDefaultVoiceSubId();
        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
            notifyEnhanced4gLteUpdate();
            return;
        }

        final VolteQueryImsState queryState = queryImsState(subId);
        final boolean currentValue = queryState.isEnabledByUser()
                && queryState.isAllowUserControl();
        if (newValue == currentValue) {
            notifyEnhanced4gLteUpdate();
            return;
        }

        // isVoLteProvisioned() is the last item to check since it might block the main thread
        if (queryState.isVoLteProvisioned()) {
            setEnhanced4gLteModeSetting(subId, newValue);
        }
        notifyEnhanced4gLteUpdate();
    }

    private void notifyEnhanced4gLteUpdate() {
        // notify change in slice in any case to get re-queried. This would result in displaying
        // appropriate message with the updated setting.
        mContext.getContentResolver().notifyChange(CustomSliceRegistry.ENHANCED_4G_SLICE_URI, null);
    }

    @VisibleForTesting
    void setEnhanced4gLteModeSetting(int subId, boolean isEnabled) {
        if (!SubscriptionManager.isValidSubscriptionId(subId)) {
            return;
        }
        final ImsMmTelManager imsMmTelManager = ImsMmTelManager.createForSubscriptionId(subId);
        if (imsMmTelManager == null) {
            return;
        }
        try {
            imsMmTelManager.setAdvancedCallingSettingEnabled(isEnabled);
        } catch (IllegalArgumentException exception) {
            Log.w(TAG, "Unable to change the Enhanced 4g LTE to " + isEnabled + ". subId=" + subId,
                    exception);
        }
    }

    private CharSequence getEnhanced4glteModeTitle(int subId) {
        final int variant4gLteTitleIndex = getCarrierConfigManagerKeyValue(
                CarrierConfigManager.KEY_ENHANCED_4G_LTE_TITLE_VARIANT_INT, subId, 0);
        final boolean show4GForLTE = isCarrierConfigManagerKeyEnabled(
                CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, subId, false);
        final CharSequence[] variantTitles = mContext.getResources()
                .getTextArray(R.array.enhanced_4g_lte_mode_title_variant);
        int index = MODE_ADVANCED_CALL;
        if (variant4gLteTitleIndex != MODE_ADVANCED_CALL) {
            index = show4GForLTE ? MODE_4G_CALLING : MODE_VOLTE;
        }
        return variantTitles[index];
    }

    /**
     * Returns {@code true} when the key is enabled for the carrier, and {@code false} otherwise.
     */
    private boolean isCarrierConfigManagerKeyEnabled(String key, int subId, boolean defaultValue) {
        boolean result = defaultValue;
        final PersistableBundle carrierConfig = getCarrierConfig(subId);
        if (carrierConfig != null) {
            result = carrierConfig.getBoolean(key, defaultValue);
        }
        return result;
    }

    private int getCarrierConfigManagerKeyValue(String key, int subId, int defaultValue) {
        int result = defaultValue;
        final PersistableBundle carrierConfig = getCarrierConfig(subId);
        if (carrierConfig != null) {
            result = carrierConfig.getInt(key, defaultValue);
        }
        return result;
    }

    private PersistableBundle getCarrierConfig(int subId) {
        final CarrierConfigManager configManager = getCarrierConfigManager();
        PersistableBundle bundle = null;
        if (configManager != null) {
            bundle = configManager.getConfigForSubId(subId);
        }
        return bundle;
    }

    protected CarrierConfigManager getCarrierConfigManager() {
        return mContext.getSystemService(CarrierConfigManager.class);
    }

    private PendingIntent getBroadcastIntent(String action) {
        final Intent intent = new Intent(action);
        intent.setClass(mContext, SliceBroadcastReceiver.class);
        return PendingIntent.getBroadcast(mContext, 0 /* requestCode */, intent,
                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
    }

    /**
     * Returns the current default voice subId obtained from SubscriptionManager
     */
    protected int getDefaultVoiceSubId() {
        return SubscriptionManager.getDefaultVoiceSubscriptionId();
    }

    /**
     * Returns PendingIntent to start activity specified by action
     */
    private PendingIntent getActivityIntent(String action) {
        final Intent intent = new Intent(action);
        intent.setPackage(SETTINGS_PACKAGE_NAME);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        return PendingIntent.getActivity(mContext, 0 /* requestCode */, intent,
                PendingIntent.FLAG_IMMUTABLE);
    }

    @VisibleForTesting
    VolteQueryImsState queryImsState(int subId) {
        return new VolteQueryImsState(mContext, subId);
    }
}

