/*
 * 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.keyguard;

import static android.view.View.INVISIBLE;

import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.res.Resources;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;

import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FakeFeatureFlags;
import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor;
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractorFactory;
import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager;
import com.android.systemui.log.LogBuffer;
import com.android.systemui.plugins.clocks.ClockAnimations;
import com.android.systemui.plugins.clocks.ClockController;
import com.android.systemui.plugins.clocks.ClockEvents;
import com.android.systemui.plugins.clocks.ClockFaceConfig;
import com.android.systemui.plugins.clocks.ClockFaceController;
import com.android.systemui.plugins.clocks.ClockFaceEvents;
import com.android.systemui.plugins.clocks.ClockTickRate;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.res.R;
import com.android.systemui.shared.clocks.AnimatableClockView;
import com.android.systemui.shared.clocks.ClockRegistry;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerAlwaysOnDisplayViewBinder;
import com.android.systemui.statusbar.phone.NotificationIconAreaController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.settings.SecureSettings;
import com.android.systemui.util.time.FakeSystemClock;

import org.junit.Before;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

public class KeyguardClockSwitchControllerBaseTest extends SysuiTestCase {

    @Mock
    protected KeyguardClockSwitch mView;
    @Mock
    protected StatusBarStateController mStatusBarStateController;
    @Mock
    protected ClockRegistry mClockRegistry;
    @Mock
    KeyguardSliceViewController mKeyguardSliceViewController;
    @Mock
    NotificationIconAreaController mNotificationIconAreaController;
    @Mock
    LockscreenSmartspaceController mSmartspaceController;

    @Mock
    Resources mResources;
    @Mock
    KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
    @Mock
    protected ClockController mClockController;
    @Mock
    protected ClockFaceController mLargeClockController;
    @Mock
    protected ClockFaceController mSmallClockController;
    @Mock
    protected ClockAnimations mClockAnimations;
    @Mock
    protected ClockEvents mClockEvents;
    @Mock
    protected ClockFaceEvents mClockFaceEvents;
    @Mock
    DumpManager mDumpManager;
    @Mock
    ClockEventController mClockEventController;

    @Mock
    protected NotificationIconContainer mNotificationIcons;
    @Mock
    protected AnimatableClockView mSmallClockView;
    @Mock
    protected AnimatableClockView mLargeClockView;
    @Mock
    protected FrameLayout mSmallClockFrame;
    @Mock
    protected FrameLayout mLargeClockFrame;
    @Mock
    protected SecureSettings mSecureSettings;
    @Mock
    protected LogBuffer mLogBuffer;

    @Mock
    protected KeyguardClockInteractor mKeyguardClockInteractor;

    protected final View mFakeDateView = (View) (new ViewGroup(mContext) {
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {}
    });
    protected final View mFakeWeatherView = new View(mContext);
    protected final View mFakeSmartspaceView = new View(mContext);

    protected KeyguardClockSwitchController mController;
    protected View mSliceView;
    protected LinearLayout mStatusArea;
    protected FakeExecutor mExecutor;
    protected FakeFeatureFlags mFakeFeatureFlags;
    @Captor protected ArgumentCaptor<View.OnAttachStateChangeListener> mAttachCaptor =
            ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);

    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);

        mFakeDateView.setTag(R.id.tag_smartspace_view, new Object());
        mFakeWeatherView.setTag(R.id.tag_smartspace_view, new Object());
        mFakeSmartspaceView.setTag(R.id.tag_smartspace_view, new Object());

        when(mView.findViewById(R.id.left_aligned_notification_icon_container))
                .thenReturn(mNotificationIcons);
        when(mNotificationIcons.getLayoutParams()).thenReturn(
                mock(RelativeLayout.LayoutParams.class));
        when(mView.getContext()).thenReturn(getContext());
        when(mView.getResources()).thenReturn(mResources);
        when(mResources.getDimensionPixelSize(R.dimen.keyguard_clock_top_margin))
                .thenReturn(100);
        when(mResources.getDimensionPixelSize(com.android.systemui.customization.R.dimen.keyguard_large_clock_top_margin))
                .thenReturn(-200);
        when(mResources.getInteger(com.android.internal.R.integer.config_doublelineClockDefault))
                .thenReturn(1);
        when(mResources.getInteger(R.integer.keyguard_date_weather_view_invisibility))
                .thenReturn(INVISIBLE);

        when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
        when(mView.findViewById(R.id.lockscreen_clock_view)).thenReturn(mSmallClockFrame);
        when(mSmallClockView.getContext()).thenReturn(getContext());
        when(mLargeClockView.getContext()).thenReturn(getContext());

        when(mView.isAttachedToWindow()).thenReturn(true);
        when(mSmartspaceController.buildAndConnectDateView(any())).thenReturn(mFakeDateView);
        when(mSmartspaceController.buildAndConnectWeatherView(any())).thenReturn(mFakeWeatherView);
        when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
        mExecutor = new FakeExecutor(new FakeSystemClock());
        mFakeFeatureFlags = new FakeFeatureFlags();
        mFakeFeatureFlags.set(LOCKSCREEN_WALLPAPER_DREAM_ENABLED, false);
        mController = new KeyguardClockSwitchController(
                mView,
                mStatusBarStateController,
                mClockRegistry,
                mKeyguardSliceViewController,
                mNotificationIconAreaController,
                mSmartspaceController,
                mock(NotificationIconContainerAlwaysOnDisplayViewBinder.class),
                mKeyguardUnlockAnimationController,
                mSecureSettings,
                mExecutor,
                mExecutor,
                mDumpManager,
                mClockEventController,
                mLogBuffer,
                KeyguardInteractorFactory.create(mFakeFeatureFlags).getKeyguardInteractor(),
                mKeyguardClockInteractor,
                mFakeFeatureFlags,
                mock(InWindowLauncherUnlockAnimationManager.class)
        );

        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE);
        when(mLargeClockController.getView()).thenReturn(mLargeClockView);
        when(mSmallClockController.getView()).thenReturn(mSmallClockView);
        when(mClockController.getLargeClock()).thenReturn(mLargeClockController);
        when(mClockController.getSmallClock()).thenReturn(mSmallClockController);
        when(mClockController.getEvents()).thenReturn(mClockEvents);
        when(mSmallClockController.getEvents()).thenReturn(mClockFaceEvents);
        when(mLargeClockController.getEvents()).thenReturn(mClockFaceEvents);
        when(mLargeClockController.getAnimations()).thenReturn(mClockAnimations);
        when(mSmallClockController.getAnimations()).thenReturn(mClockAnimations);
        when(mClockRegistry.createCurrentClock()).thenReturn(mClockController);
        when(mClockEventController.getClock()).thenReturn(mClockController);
        when(mSmallClockController.getConfig())
                .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false, false));
        when(mLargeClockController.getConfig())
                .thenReturn(new ClockFaceConfig(ClockTickRate.PER_MINUTE, false, false, false));

        mSliceView = new View(getContext());
        when(mView.findViewById(R.id.keyguard_slice_view)).thenReturn(mSliceView);
        mStatusArea = new LinearLayout(getContext());
        when(mView.findViewById(R.id.keyguard_status_area)).thenReturn(mStatusArea);
    }

    private void removeView(View v) {
        ViewGroup group = ((ViewGroup) v.getParent());
        if (group != null) {
            group.removeView(v);
        }
    }

    protected void init() {
        mController.init();

        verify(mView, atLeast(1)).addOnAttachStateChangeListener(mAttachCaptor.capture());
        mAttachCaptor.getValue().onViewAttachedToWindow(mView);
    }
}
