/*
 * Copyright (C) 2024 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.display;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;

import com.android.settings.R;
import com.android.settings.connecteddevice.DevicePreferenceCallback;
import com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.DisplayListener;
import com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.Injector;
import com.android.settings.core.SubSettingLauncher;
import com.android.settings.overlay.FeatureFactory;
import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtilsInternal;
import com.android.settingslib.RestrictedPreference;
import com.android.settingslib.core.instrumentation.MetricsFeatureProvider;

public class ExternalDisplayUpdater {

    private static final String PREF_KEY = "external_display_settings";
    private final int mMetricsCategory;
    @NonNull
    private final MetricsFeatureProvider mMetricsFeatureProvider;
    @NonNull
    private final Runnable mUpdateRunnable = this::update;
    @NonNull
    private final DevicePreferenceCallback mDevicePreferenceCallback;
    @Nullable
    private RestrictedPreference mPreference;
    @Nullable
    private Injector mInjector;
    private final DisplayListener mListener =  new DisplayListener() {
        @Override
        public void update(int displayId) {
            refreshPreference();
        }
    };

    public ExternalDisplayUpdater(@NonNull DevicePreferenceCallback callback, int metricsCategory) {
        mDevicePreferenceCallback = callback;
        mMetricsCategory = metricsCategory;
        mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider();
    }

    /**
     * Set the context to generate the {@link Preference}, so it could get the correct theme.
     */
    public void initPreference(@NonNull Context context) {
        initPreference(context, new Injector(context));
    }

    @VisibleForTesting
    void initPreference(@NonNull Context context, Injector injector) {
        mInjector = injector;
        mPreference = new RestrictedPreference(context, null /* AttributeSet */);
        mPreference.setTitle(R.string.external_display_settings_title);
        mPreference.setSummary(getSummary());
        mPreference.setIcon(getDrawable(context));
        mPreference.setKey(PREF_KEY);
        mPreference.setDisabledByAdmin(checkIfUsbDataSignalingIsDisabled(context));
        mPreference.setOnPreferenceClickListener((Preference p) -> {
            mMetricsFeatureProvider.logClickedPreference(p, mMetricsCategory);
            // New version - uses a separate screen.
            new SubSettingLauncher(context)
                    .setDestination(ExternalDisplayPreferenceFragment.class.getName())
                    .setTitleRes(R.string.external_display_settings_title)
                    .setSourceMetricsCategory(mMetricsCategory)
                    .launch();
            return true;
        });
    }

    /**
     * Unregister the display listener.
     */
    public void unregisterCallback() {
        if (mInjector != null) {
            mInjector.unregisterDisplayListener(mListener);
        }
    }

    /**
     * Register the display listener.
     */
    public void registerCallback() {
        if (mInjector != null) {
            mInjector.registerDisplayListener(mListener);
        }
    }

    @VisibleForTesting
    @Nullable
    protected RestrictedLockUtils.EnforcedAdmin checkIfUsbDataSignalingIsDisabled(Context context) {
        return RestrictedLockUtilsInternal.checkIfUsbDataSignalingIsDisabled(context,
                    UserHandle.myUserId());
    }

    @VisibleForTesting
    @Nullable
    protected Drawable getDrawable(Context context) {
        return context.getDrawable(R.drawable.ic_external_display_32dp);
    }

    @Nullable
    protected CharSequence getSummary() {
        if (mInjector == null) {
            return null;
        }
        var context = mInjector.getContext();
        if (context == null) {
            return null;
        }

        var allDisplays = mInjector.getConnectedDisplays();
        for (var display : allDisplays) {
            if (display.isEnabled() == DisplayIsEnabled.YES) {
                return context.getString(R.string.external_display_on);
            }
        }
        return allDisplays.isEmpty() ? null : context.getString(R.string.external_display_off);
    }

    /**
     * Updates preference, possibly removing it entirely.
     */
    public void refreshPreference() {
        if (mInjector == null) {
            return;
        }
        unscheduleUpdate();
        mInjector.getHandler().post(mUpdateRunnable);
    }

    private void unscheduleUpdate() {
        if (mInjector == null) {
            return;
        }
        mInjector.getHandler().removeCallbacks(mUpdateRunnable);
    }

    private void update() {
        var summary = getSummary();
        if (mPreference == null) {
            return;
        }
        mPreference.setSummary(summary);
        if (summary != null) {
            mDevicePreferenceCallback.onDeviceAdded(mPreference);
        } else {
            mDevicePreferenceCallback.onDeviceRemoved(mPreference);
        }
    }
}
