// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.components.autofill_assistant;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ScrollView;

import androidx.annotation.Nullable;

import org.chromium.base.Callback;
import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.base.supplier.Supplier;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetContent;

/**
 * The {@link BottomSheetContent} for the Autofill Assistant. It supports notifying the
 * BottomSheet when its size changes and allows to dynamically set its scrollable content (in
 * practice, this allows to replace the onboarding by the actual Autofill Assistant content).
 */
public class AssistantBottomSheetContent implements BottomSheetContent {
    private final View mToolbarView;
    private final SizeListenableLinearLayout mContentView;
    @Nullable
    private ScrollView mContentScrollableView;
    private Supplier<AssistantBottomBarDelegate> mBottomBarDelegateSupplier;
    private boolean mPeekModeDisabled;
    @Nullable
    private Callback<Integer> mOffsetController;
    private final ObservableSupplierImpl<Boolean> mBackPressStateChangedSupplier =
            new ObservableSupplierImpl<>();

    public AssistantBottomSheetContent(
            Context context, Supplier<AssistantBottomBarDelegate> supplier) {
        mToolbarView = LayoutUtils.createInflater(context).inflate(
                R.layout.autofill_assistant_bottom_sheet_toolbar, /* root= */ null);
        mContentView = new SizeListenableLinearLayout(context);
        mContentView.setLayoutParams(new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        mContentView.setTag(
                AutofillAssistantPublicTags.AUTOFILL_ASSISTANT_BOTTOM_SHEET_CONTENT_TAG);
        mBottomBarDelegateSupplier = supplier;
    }

    public void setContent(View content, ScrollView scrollableView) {
        if (mContentView.getChildCount() > 0) {
            mContentView.removeAllViews();
        }

        content.setLayoutParams(new ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
        mContentView.addView(content);
        mContentScrollableView = scrollableView;
    }

    public void setDelegate(Supplier<AssistantBottomBarDelegate> supplier) {
        mBottomBarDelegateSupplier = supplier;
    }

    /**
     * Initialize or update back press handling behavior by sheet content ahead-of-time. If never
     * invoked after content initialization, it will be assumed that sheet content will not handle a
     * back press.
     */
    public void setHandleBackPress(boolean handleBackPress) {
        mBackPressStateChangedSupplier.set(handleBackPress);
    }

    public void setPeekModeDisabled(boolean disabled) {
        mPeekModeDisabled = disabled;
    }

    @Override
    public View getContentView() {
        return mContentView;
    }

    @Nullable
    @Override
    public View getToolbarView() {
        return mToolbarView;
    }

    @Override
    public int getVerticalScrollOffset() {
        if (mContentScrollableView != null) {
            return mContentScrollableView.getScrollY();
        }

        return 0;
    }

    @Override
    public boolean setContentSizeListener(@Nullable ContentSizeListener listener) {
        mContentView.setContentSizeListener(listener);
        return true;
    }

    @Override
    public void destroy() {}

    @Override
    public int getPriority() {
        return BottomSheetContent.ContentPriority.HIGH;
    }

    @Override
    public boolean swipeToDismissEnabled() {
        return false;
    }

    @Override
    public float getFullHeightRatio() {
        return BottomSheetContent.HeightMode.WRAP_CONTENT;
    }

    @Override
    public boolean hasCustomLifecycle() {
        return true;
    }

    @Override
    public boolean hasCustomScrimLifecycle() {
        return true;
    }

    @Override
    public int getPeekHeight() {
        return mPeekModeDisabled ? BottomSheetContent.HeightMode.DISABLED
                                 : BottomSheetContent.HeightMode.DEFAULT;
    }

    @Override
    public boolean hideOnScroll() {
        return false;
    }

    @Override
    public int getSheetContentDescriptionStringId() {
        return R.string.autofill_assistant_sheet_content_description;
    }

    @Override
    public int getSheetHalfHeightAccessibilityStringId() {
        return R.string.autofill_assistant_sheet_half_height;
    }

    @Override
    public int getSheetFullHeightAccessibilityStringId() {
        return R.string.autofill_assistant_sheet_full_height;
    }

    @Override
    public int getSheetClosedAccessibilityStringId() {
        return R.string.autofill_assistant_sheet_closed;
    }

    @Override
    public boolean handleBackPress() {
        AssistantBottomBarDelegate bottomBarDelegate = mBottomBarDelegateSupplier.get();
        if (bottomBarDelegate == null) {
            return false;
        }

        return bottomBarDelegate.onBackButtonPressed();
    }

    @Override
    public ObservableSupplierImpl<Boolean> getBackPressStateChangedSupplier() {
        return mBackPressStateChangedSupplier;
    }

    @Override
    public void onBackPressed() {
        if (mBottomBarDelegateSupplier.get() != null) {
            mBottomBarDelegateSupplier.get().onBackButtonPressed();
        }
    }

    @Override
    public boolean contentControlsOffset() {
        return true;
    }

    @Override
    public void setOffsetController(Callback<Integer> offsetController) {
        mOffsetController = offsetController;
    }

    public Callback<Integer> getOffsetController() {
        return mOffsetController;
    }
}
