/*
 * Copyright (C) 2023 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.connecteddevice.audiosharing;

import static com.android.settings.connecteddevice.audiosharing.AudioSharingUtils.isBroadcasting;

import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.preference.PreferenceScreen;

import com.android.settings.R;
import com.android.settings.bluetooth.Utils;
import com.android.settings.core.BasePreferenceController;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.ValidatedEditTextPreference;
import com.android.settingslib.bluetooth.LocalBluetoothLeBroadcast;
import com.android.settingslib.bluetooth.LocalBluetoothManager;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;
import com.android.settingslib.utils.ThreadUtils;

import java.nio.charset.StandardCharsets;

public class AudioSharingPasswordPreferenceController extends BasePreferenceController
        implements ValidatedEditTextPreference.Validator,
                AudioSharingPasswordPreference.OnDialogEventListener {

    private static final String TAG = "AudioSharingPasswordPreferenceController";
    private static final String PREF_KEY = "audio_sharing_stream_password";
    private static final String SHARED_PREF_NAME = "audio_sharing_settings";
    private static final String SHARED_PREF_KEY = "default_password";
    @Nullable private final LocalBluetoothManager mBtManager;
    @Nullable private final LocalBluetoothLeBroadcast mBroadcast;
    @Nullable private AudioSharingPasswordPreference mPreference;
    private final AudioSharingPasswordValidator mAudioSharingPasswordValidator;
    private final MetricsFeatureProvider mMetricsFeatureProvider;

    public AudioSharingPasswordPreferenceController(Context context, String preferenceKey) {
        super(context, preferenceKey);
        mBtManager = Utils.getLocalBluetoothManager(context);
        mBroadcast =
                mBtManager != null
                        ? mBtManager.getProfileManager().getLeAudioBroadcastProfile()
                        : null;
        mAudioSharingPasswordValidator = new AudioSharingPasswordValidator();
        mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
    }

    @Override
    public int getAvailabilityStatus() {
        return AudioSharingUtils.isFeatureEnabled() ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
    }

    @Override
    public void displayPreference(PreferenceScreen screen) {
        super.displayPreference(screen);
        mPreference = screen.findPreference(getPreferenceKey());
        if (mPreference != null) {
            mPreference.setValidator(this);
            mPreference.setIsPassword(true);
            mPreference.setDialogLayoutResource(R.layout.audio_sharing_password_dialog);
            mPreference.setOnDialogEventListener(this);
            updatePreference();
        }
    }

    @Override
    public String getPreferenceKey() {
        return PREF_KEY;
    }

    @Override
    public boolean isTextValid(String value) {
        return mAudioSharingPasswordValidator.isTextValid(value);
    }

    @Override
    public void onBindDialogView() {
        if (mPreference == null || mBroadcast == null) {
            return;
        }
        mPreference.setEditable(!isBroadcasting(mBtManager));
        var password = mBroadcast.getBroadcastCode();
        mPreference.setChecked(isPublicBroadcast(password));
    }

    @Override
    public void onPreferenceDataChanged(@NonNull String password, boolean isPublicBroadcast) {
        var unused =
                ThreadUtils.postOnBackgroundThread(
                        () -> {
                            if (mBroadcast == null || isBroadcasting(mBtManager)) {
                                Log.w(
                                        TAG,
                                        "onPreferenceDataChanged() changing password when"
                                                + " broadcasting or null!");
                                return;
                            }
                            boolean isCurrentPublicBroadcast =
                                    isPublicBroadcast(mBroadcast.getBroadcastCode());
                            String currentDefaultPassword = getDefaultPassword(mContext);
                            if (password.equals(currentDefaultPassword)
                                    && isCurrentPublicBroadcast == isPublicBroadcast) {
                                Log.d(TAG, "onPreferenceDataChanged() nothing changed");
                                return;
                            }
                            persistDefaultPassword(mContext, password);
                            mBroadcast.setBroadcastCode(
                                    isPublicBroadcast ? new byte[0] : password.getBytes());
                            updatePreference();
                            mMetricsFeatureProvider.action(
                                    mContext,
                                    SettingsEnums.ACTION_AUDIO_STREAM_PASSWORD_UPDATED,
                                    isPublicBroadcast ? 1 : 0);
                        });
    }

    private void updatePreference() {
        if (mBroadcast == null || mPreference == null) {
            return;
        }
        var unused =
                ThreadUtils.postOnBackgroundThread(
                        () -> {
                            byte[] password = mBroadcast.getBroadcastCode();
                            boolean noPassword = isPublicBroadcast(password);
                            String passwordToDisplay =
                                    noPassword
                                            ? getDefaultPassword(mContext)
                                            : new String(password, StandardCharsets.UTF_8);
                            String passwordSummary =
                                    noPassword
                                            ? mContext.getString(
                                                    R.string.audio_streams_no_password_summary)
                                            : "********";

                            AudioSharingUtils.postOnMainThread(
                                    mContext,
                                    () -> {
                                        // Check nullability to pass NullAway check
                                        if (mPreference != null) {
                                            mPreference.setText(passwordToDisplay);
                                            mPreference.setSummary(passwordSummary);
                                        }
                                    });
                        });
    }

    private static void persistDefaultPassword(Context context, String defaultPassword) {
        if (getDefaultPassword(context).equals(defaultPassword)) {
            return;
        }

        SharedPreferences sharedPref =
                context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
        if (sharedPref == null) {
            Log.w(TAG, "persistDefaultPassword(): sharedPref is empty!");
            return;
        }

        SharedPreferences.Editor editor = sharedPref.edit();
        editor.putString(SHARED_PREF_KEY, defaultPassword);
        editor.apply();
    }

    private static String getDefaultPassword(Context context) {
        SharedPreferences sharedPref =
                context.getSharedPreferences(SHARED_PREF_NAME, Context.MODE_PRIVATE);
        if (sharedPref == null) {
            Log.w(TAG, "getDefaultPassword(): sharedPref is empty!");
            return "";
        }

        String value = sharedPref.getString(SHARED_PREF_KEY, "");
        if (value != null && value.isEmpty()) {
            Log.w(TAG, "getDefaultPassword(): default password is empty!");
        }
        return value;
    }

    private static boolean isPublicBroadcast(@Nullable byte[] password) {
        return password == null || password.length == 0;
    }
}
