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

import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;

import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;

import com.android.settings.R;

import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;

import java.util.ArrayList;
import java.util.Arrays;

public class TrackpadGestureDialogFragment extends BottomSheetDialogFragment {

    private Context mContext;
    private LayoutInflater mInflater;
    private View mViewArrowPrevious;
    private View mViewArrowNext;
    private ViewPager mViewPager;
    private ArrayList<View> mPageList;
    private ImageView[] mDotIndicators;
    private View[] mViewPagerItems;
    private Button mButtonStartSkip;
    private Button mButtonStartRestart;
    private Button mButtonEndNext;
    private Button mButtonEndDone;

    private static final int DOT_INDICATOR_SIZE = 12;
    private static final int DOT_INDICATOR_LEFT_PADDING = 6;
    private static final int DOT_INDICATOR_RIGHT_PADDING = 6;

    public TrackpadGestureDialogFragment() {}

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mContext = context;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onStart() {
        super.onStart();
        final Dialog dialog = getDialog();
        if (dialog == null) {
            return;
        }
        Window window = dialog.getWindow();
        if (window == null) {
            return;
        }
        setLayoutEdgeToEdge(window);
        final Point size = getScreenSize();
        final WindowManager.LayoutParams attributes = window.getAttributes();
        attributes.width = (int) (size.x * 0.75);
        window.setAttributes(attributes);
    }

    @Override
    public void onPause() {
        super.onPause();
        dismiss();
    }

    private static void setLayoutEdgeToEdge(Window window) {
        View windowDecorView = window.getDecorView();
        windowDecorView.setSystemUiVisibility(
                windowDecorView.getSystemUiVisibility()
                        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
        window.setNavigationBarColor(Color.TRANSPARENT);
    }

    @Override
    public Dialog onCreateDialog(final Bundle savedInstanceState) {
        Dialog dialog = super.onCreateDialog(savedInstanceState);

        mInflater = mContext.getSystemService(LayoutInflater.class);
        View contentView = mInflater.inflate(R.layout.trackpad_gesture_preview, null);
        addViewPager(contentView);
        dialog.setContentView(contentView);
        Window gestureDialogWindow = dialog.getWindow();
        gestureDialogWindow.setType(TYPE_SYSTEM_DIALOG);

        // Workaround for solve issue about dialog not full expanded when landscape.
        FrameLayout bottomSheet = (FrameLayout)
                dialog.findViewById(com.google.android.material.R.id.design_bottom_sheet);
        bottomSheet.setBackgroundResource(android.R.color.transparent);
        BottomSheetBehavior<FrameLayout> behavior = BottomSheetBehavior.from(bottomSheet);
        if (!isGestureNavigationEnabled()) {
            behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
        }
        ViewTreeObserver observer = contentView.getViewTreeObserver();
        observer.addOnGlobalLayoutListener(
                new ViewTreeObserver.OnGlobalLayoutListener() {
                    @Override
                    public void onGlobalLayout() {
                        contentView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                        int contentViewHeight = contentView.getMeasuredHeight();
                        int navigationBarHeight = getNavigationBarHeight();
                        behavior.setPeekHeight(contentViewHeight - navigationBarHeight);
                    }
                });

        // The gesture education view shouldn't be draggable."
        behavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(View bottomSheet, int newState) {
                if (newState == BottomSheetBehavior.STATE_DRAGGING) {
                    if (isGestureNavigationEnabled()) {
                        behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                    } else {
                        behavior.setState(BottomSheetBehavior.STATE_EXPANDED);
                    }
                }
            }

            @Override
            public void onSlide(View bottomSheet, float slideOffset) {
                // Do nothing.
            }
        });

        return dialog;
    }

    private ArrayList<Integer> getViewPagerResource() {
        return new ArrayList<Integer>(
                Arrays.asList(
                        R.layout.gesture_tip1_go_home,
                        R.layout.gesture_tip2_go_back,
                        R.layout.gesture_tip3_recent_apps,
                        R.layout.gesture_tip4_notifications,
                        R.layout.gesture_tip5_switch_apps));
    }

    private void addViewPager(View preview) {
        mViewPager = preview.findViewById(R.id.viewpager);
        int viewPagerResourceSize = getViewPagerResource().size();
        mViewPagerItems = new View[viewPagerResourceSize];
        for (int i = 0; i < viewPagerResourceSize; i++) {
            mViewPagerItems[i] =
                    mInflater.inflate(getViewPagerResource().get(i), null /* root */);
        }

        mPageList = new ArrayList<View>();
        for (int i = 0; i < mViewPagerItems.length; i++) {
            mPageList.add(mViewPagerItems[i]);
        }

        mViewPager.setAdapter(new GesturePagerAdapter(mPageList));

        mButtonStartRestart = (Button) preview.findViewById(R.id.button_restart);
        mButtonStartRestart.setOnClickListener(v -> {
            final int firstPos = mViewPager.getCurrentItem() - mViewPagerItems.length;
            mViewPager.setCurrentItem(firstPos, true);
        });

        mButtonEndDone = (Button) preview.findViewById(R.id.button_done);
        mButtonEndDone.setOnClickListener(v -> {
            dismiss();
        });

        mButtonStartSkip = (Button) preview.findViewById(R.id.button_skip);
        mButtonStartSkip.setOnClickListener(v -> {
            dismiss();
        });

        mButtonEndNext = (Button) preview.findViewById(R.id.button_next);
        mButtonEndNext.setOnClickListener(v -> {
            final int nextPos = mViewPager.getCurrentItem() + 1;
            mViewPager.setCurrentItem(nextPos, true);
        });

        mViewPager.addOnPageChangeListener(createPageListener());
        final ViewGroup viewGroup = (ViewGroup) preview.findViewById(R.id.viewGroup);
        mDotIndicators = new ImageView[mPageList.size()];
        for (int i = 0; i < mPageList.size(); i++) {
            final ImageView imageView = new ImageView(mContext);
            final ViewGroup.MarginLayoutParams lp =
                    new ViewGroup.MarginLayoutParams(DOT_INDICATOR_SIZE, DOT_INDICATOR_SIZE);
            lp.setMargins(DOT_INDICATOR_LEFT_PADDING, 0, DOT_INDICATOR_RIGHT_PADDING, 0);
            imageView.setLayoutParams(lp);
            mDotIndicators[i] = imageView;
            viewGroup.addView(mDotIndicators[i]);
        }
    }

    private static class GesturePagerAdapter extends PagerAdapter {
        private final ArrayList<View> mPageViewList;

        GesturePagerAdapter(ArrayList<View> pageViewList) {
            mPageViewList = pageViewList;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            if (mPageViewList.get(position) != null) {
                container.removeView(mPageViewList.get(position));
            }
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            container.addView(mPageViewList.get(position));
            return mPageViewList.get(position);
        }

        @Override
        public int getCount() {
            return mPageViewList.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return object == view;
        }
    }

    private ViewPager.OnPageChangeListener createPageListener() {
        return new ViewPager.OnPageChangeListener() {
            @Override
            public void onPageScrolled(
                    int position, float positionOffset, int positionOffsetPixels) {
                if (positionOffset != 0) {
                    for (int i = 0; i < mPageList.size(); i++) {
                        mViewPagerItems[i].setVisibility(View.VISIBLE);
                    }
                } else {
                    updateIndicator(position);
                }
            }

            @Override
            public void onPageSelected(int position) {}

            @Override
            public void onPageScrollStateChanged(int state) {}
        };
    }

    private void updateIndicator(int position) {
        for (int i = 0; i < mPageList.size(); i++) {
            if (position == i) {
                mDotIndicators[i].setBackgroundResource(
                        R.drawable.ic_color_page_indicator_focused);
                mViewPagerItems[i].setVisibility(View.VISIBLE);
            } else {
                mDotIndicators[i].setBackgroundResource(
                        R.drawable.ic_color_page_indicator_unfocused);
                mViewPagerItems[i].setVisibility(View.INVISIBLE);
            }
        }

        if (position >= 0 && position < mViewPagerItems.length - 1) {
            mButtonStartSkip.setVisibility(View.VISIBLE);
            mButtonEndNext.setVisibility(View.VISIBLE);
            mButtonStartRestart.setVisibility(View.GONE);
            mButtonEndDone.setVisibility(View.GONE);
        } else {
            mButtonStartSkip.setVisibility(View.GONE);
            mButtonEndNext.setVisibility(View.GONE);
            mButtonStartRestart.setVisibility(View.VISIBLE);
            mButtonEndDone.setVisibility(View.VISIBLE);
        }
    }

    private Point getScreenSize() {
        final Point size = new Point();
        final Activity activity = (Activity) mContext;
        final Display display = activity.getWindowManager().getDefaultDisplay();
        display.getSize(size);
        return size;
    }

    private int getNavigationBarHeight() {
        final Activity activity = (Activity) mContext;
        WindowInsets insets =
                activity.getWindowManager().getCurrentWindowMetrics().getWindowInsets();
        return insets.getInsets(WindowInsets.Type.navigationBars()).bottom;
    }

    private boolean isGestureNavigationEnabled() {
        return NAV_BAR_MODE_GESTURAL == mContext.getResources().getInteger(
                com.android.internal.R.integer.config_navBarInteractionMode);
    }
}
