// Copyright 2021 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.chrome.browser.feed.webfeed;

import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;

import org.chromium.base.Callback;
import org.chromium.base.Log;
import org.chromium.base.task.PostTask;
import org.chromium.base.task.TaskTraits;
import org.chromium.chrome.browser.feed.FeedFeatures;
import org.chromium.chrome.browser.feed.FeedServiceBridge;
import org.chromium.chrome.browser.feed.R;
import org.chromium.chrome.browser.feed.SingleWebFeedEntryPoint;
import org.chromium.chrome.browser.feed.StreamKind;
import org.chromium.chrome.browser.feed.componentinterfaces.SurfaceCoordinator.StreamTabId;
import org.chromium.chrome.browser.feed.v2.FeedUserActionType;
import org.chromium.chrome.browser.feed.webfeed.WebFeedBridge.FollowResults;
import org.chromium.chrome.browser.feed.webfeed.WebFeedBridge.WebFeedMetadata;
import org.chromium.chrome.browser.feed.webfeed.WebFeedSnackbarController.FeedLauncher;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler;
import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
import org.chromium.components.browser_ui.widget.chips.ChipView;
import org.chromium.components.prefs.PrefService;
import org.chromium.components.url_formatter.UrlFormatter;
import org.chromium.ui.modaldialog.ModalDialogManager;
import org.chromium.ui.widget.LoadingView;
import org.chromium.url.GURL;

/**
 * Specific {@link FrameLayout} that displays the Web Feed footer in the main menu.
 */
public class WebFeedMainMenuItem extends FrameLayout {
    private static final String TAG = "WebFeedMainMenuItem";
    private static final int LOADING_REFRESH_TIME_MS = 400;

    private Context mContext;

    private GURL mUrl;
    private Tab mTab;
    private String mTitle;
    private AppMenuHandler mAppMenuHandler;
    private Class<?> mCreatorActivityClass;

    // Points to the currently shown chip: null, mFollowingChipView, mFollowChipView,
    private ChipView mChipView;

    // Child views, null before inflation.
    private ChipView mFollowingChipView;
    private ChipView mFollowChipView;
    private ImageView mIcon;
    private TextView mItemText;

    private @Nullable byte[] mRecommendedWebFeedName;

    private WebFeedFaviconFetcher mFaviconFetcher;
    private WebFeedSnackbarController mWebFeedSnackbarController;

    /**
     * Constructs a new {@link WebFeedMainMenuItem} with the appropriate context.
     */
    public WebFeedMainMenuItem(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mIcon = findViewById(R.id.icon);
        mFollowingChipView = findViewById(R.id.following_chip_view);
        mFollowChipView = findViewById(R.id.follow_chip_view);
        mItemText = findViewById(R.id.menu_item_text);

        final ColorStateList textColor = AppCompatResources.getColorStateList(
                mContext, R.color.default_text_color_accent1_tint_list);
        mFollowingChipView.getPrimaryTextView().setTextColor(textColor);
        mFollowChipView.getPrimaryTextView().setTextColor(textColor);
        final ColorStateList backgroundColor = AppCompatResources.getColorStateList(
                mContext, R.color.menu_footer_chip_background_list);
        mFollowChipView.setBackgroundTintList(backgroundColor);
    }

    /**
     * Initialize the Web Feed main menu item.
     *
     * @param tab The current {@link Tab}.
     * @param appMenuHandler {@link AppMenuHandler} to control hiding the app menu.
     * @param feedLauncher {@link FeedLauncher}
     * @param largeIconBridge {@link LargeIconBridge} to get the favicon of the page.
     * @param dialogManager {@link ModalDialogManager} for managing the dialog.
     * @param snackbarManager {@link SnackbarManager} to display snackbars.
     * @param creatorActivityClass {@link CreatorActivity} for launching the Creator Activity.
     */
    public void initialize(Tab tab, AppMenuHandler appMenuHandler,
            WebFeedFaviconFetcher faviconFetcher, FeedLauncher feedLauncher,
            ModalDialogManager dialogManager, SnackbarManager snackbarManager,
            Class<?> creatorActivityClass) {
        mUrl = tab.getOriginalUrl();
        mTab = tab;
        mAppMenuHandler = appMenuHandler;
        mFaviconFetcher = faviconFetcher;
        mWebFeedSnackbarController = new WebFeedSnackbarController(
                mContext, feedLauncher, dialogManager, snackbarManager);
        mCreatorActivityClass = creatorActivityClass;
        Callback<WebFeedMetadata> metadataCallback = result -> {
            initializeFavicon(result);
            initializeText(result);
            initializeChipView(result);

            if (mChipView != null && mTab.isShowingErrorPage()) {
                mChipView.setEnabled(false);
            }
        };
        mRecommendedWebFeedName =
                WebFeedRecommendationFollowAcceleratorController.getWebFeedNameIfPageIsRecommended(
                        mTab);
        if (mRecommendedWebFeedName != null) {
            WebFeedBridge.getWebFeedMetadata(mRecommendedWebFeedName, metadataCallback);
        } else {
            WebFeedBridge.getWebFeedMetadataForPage(mTab, mUrl,
                    WebFeedPageInformationRequestReason.MENU_ITEM_PRESENTATION, metadataCallback);
        }
    }

    private void initializeFavicon(@Nullable WebFeedMetadata webFeedMetadata) {
        mFaviconFetcher.beginFetch(
                mContext.getResources().getDimensionPixelSize(R.dimen.web_feed_icon_size),
                mContext.getResources().getDimensionPixelSize(R.dimen.web_feed_monogram_text_size),
                mUrl, webFeedMetadata != null ? webFeedMetadata.faviconUrl : null,
                this::onFaviconFetched);
    }

    public void setContextForTest(Context newContext) {
        mContext = newContext;
    }

    private void initializeText(@Nullable WebFeedMetadata webFeedMetadata) {
        if (webFeedMetadata != null && !TextUtils.isEmpty(webFeedMetadata.title)) {
            mTitle = webFeedMetadata.title;
        } else {
            mTitle = UrlFormatter.formatUrlForDisplayOmitSchemePathAndTrivialSubdomains(mUrl);
        }
        mItemText.setText(mTitle);
        if (ChromeFeatureList.isEnabled(ChromeFeatureList.CORMORANT)) {
            mItemText.setContentDescription(
                    mContext.getString(R.string.cormorant_creator_preview, mTitle));
            mItemText.setOnClickListener((view) -> {
                PostTask.postTask(TaskTraits.UI_DEFAULT, this::launchCreatorActivity);
            });
        }
    }

    private void initializeChipView(@Nullable WebFeedMetadata webFeedMetadata) {
        @WebFeedSubscriptionStatus
        int subscriptionStatus = webFeedMetadata == null ? WebFeedSubscriptionStatus.UNKNOWN
                                                         : webFeedMetadata.subscriptionStatus;
        if (subscriptionStatus == WebFeedSubscriptionStatus.UNKNOWN
                || subscriptionStatus == WebFeedSubscriptionStatus.NOT_SUBSCRIBED) {
            hideCurrentChipAndThen(this::showUnsubscribedChipView);
        } else if (subscriptionStatus == WebFeedSubscriptionStatus.SUBSCRIBED) {
            hideCurrentChipAndThen(() -> showSubscribedChipView(webFeedMetadata.id));
        } else if (subscriptionStatus == WebFeedSubscriptionStatus.UNSUBSCRIBE_IN_PROGRESS) {
            showLoadingChipView(mFollowingChipView, mContext.getText(R.string.menu_following));
        } else if (subscriptionStatus == WebFeedSubscriptionStatus.SUBSCRIBE_IN_PROGRESS) {
            showLoadingChipView(mFollowChipView, mContext.getText(R.string.menu_follow));
        }
    }

    private void showUnsubscribedChipView() {
        mChipView = mFollowChipView;
        showEnabledChipView(mFollowChipView, mContext.getText(R.string.menu_follow),
                R.drawable.ic_add, (view) -> {
                    Callback<FollowResults> onFollowComplete = result -> {
                        byte[] followId = result.metadata != null ? result.metadata.id : null;
                        mWebFeedSnackbarController.showPostFollowHelp(mTab, result, followId, mUrl,
                                mTitle, WebFeedBridge.CHANGE_REASON_WEB_PAGE_MENU);
                        PrefService prefs = FeedFeatures.getPrefService();
                        if (!prefs.getBoolean(Pref.ARTICLES_LIST_VISIBLE)) {
                            prefs.setBoolean(Pref.ARTICLES_LIST_VISIBLE, true);
                            FeedFeatures.setLastSeenFeedTabId(StreamTabId.FOLLOWING);
                        }
                    };
                    if (mRecommendedWebFeedName != null) {
                        WebFeedBridge.followFromId(mRecommendedWebFeedName, /*isDurable=*/false,
                                WebFeedBridge.CHANGE_REASON_WEB_PAGE_MENU, onFollowComplete);
                    } else {
                        WebFeedBridge.followFromUrl(mTab, mUrl,
                                WebFeedBridge.CHANGE_REASON_WEB_PAGE_MENU, onFollowComplete);
                    }
                    WebFeedBridge.incrementFollowedFromWebPageMenuCount();
                    FeedServiceBridge.reportOtherUserAction(
                            StreamKind.UNKNOWN, FeedUserActionType.TAPPED_FOLLOW_BUTTON);
                    mAppMenuHandler.hideAppMenu();
                });
    }

    private void showSubscribedChipView(byte[] webFeedId) {
        mChipView = mFollowingChipView;
        showEnabledChipView(mFollowingChipView, mContext.getText(R.string.menu_following),
                R.drawable.ic_check_googblue_24dp, (view) -> {
                    WebFeedBridge.unfollow(webFeedId, /*isDurable=*/false,
                            WebFeedBridge.CHANGE_REASON_WEB_PAGE_MENU,
                            (result)
                                    -> mWebFeedSnackbarController.showSnackbarForUnfollow(
                                            result.requestStatus, webFeedId, mTab, mUrl, mTitle,
                                            WebFeedBridge.CHANGE_REASON_WEB_PAGE_MENU));
                    mAppMenuHandler.hideAppMenu();
                });
    }

    private void showLoadingChipView(ChipView chipView, CharSequence chipText) {
        mChipView = chipView;
        if (chipView.getVisibility() == View.GONE) {
            TextView chipTextView = chipView.getPrimaryTextView();
            chipTextView.setText(chipText);
            chipView.setEnabled(false);
            chipView.setVisibility(View.INVISIBLE);
            chipView.showLoadingView(new LoadingView.Observer() {
                boolean mCalled;
                @Override
                public void onShowLoadingUIComplete() {
                    if (mCalled) {
                        return;
                    }
                    mCalled = true;
                    chipView.setVisibility(View.VISIBLE);
                }

                @Override
                public void onHideLoadingUIComplete() {}
            });
        }
        postDelayed(()
                            -> WebFeedBridge.getWebFeedMetadataForPage(mTab, mUrl,
                                    WebFeedPageInformationRequestReason.MENU_ITEM_PRESENTATION,
                                    this::initializeChipView),
                LOADING_REFRESH_TIME_MS);
    }

    private void hideCurrentChipAndThen(Runnable afterHidden) {
        if (mChipView != null) {
            ChipView chip = mChipView;
            mChipView.hideLoadingView(new LoadingView.Observer() {
                boolean mCalled;

                @Override
                public void onShowLoadingUIComplete() {}

                @Override
                public void onHideLoadingUIComplete() {
                    if (mCalled) {
                        return;
                    }
                    mCalled = true;
                    chip.setVisibility(View.GONE);
                    afterHidden.run();
                }
            });
        } else {
            afterHidden.run();
        }
    }

    private void showEnabledChipView(ChipView chipView, CharSequence chipText,
            @DrawableRes int chipIconRes, OnClickListener onClickListener) {
        TextView chipTextView = chipView.getPrimaryTextView();
        chipTextView.setText(chipText);
        chipView.setIcon(chipIconRes, /*tintWithTextColor=*/true);
        chipView.setOnClickListener(onClickListener);
        chipView.setEnabled(!mTab.isShowingErrorPage());
        chipView.setVisibility(View.VISIBLE);
    }

    private void onFaviconFetched(Bitmap icon) {
        mIcon.setImageBitmap(icon);
        if (icon == null) {
            mIcon.setVisibility(View.GONE);
        }
        if (ChromeFeatureList.isEnabled(ChromeFeatureList.CORMORANT)) {
            mIcon.setOnClickListener((view) -> {
                PostTask.postTask(TaskTraits.UI_DEFAULT, this::launchCreatorActivity);
            });
        }
    }

    private void launchCreatorActivity() {
        try {
            // Launch a new activity for the creator page.
            Intent intent = new Intent(mContext, mCreatorActivityClass);
            if (mRecommendedWebFeedName != null) {
                intent.putExtra(
                        CreatorIntentConstants.CREATOR_WEB_FEED_ID, mRecommendedWebFeedName);
            }
            intent.putExtra(CreatorIntentConstants.CREATOR_URL, mUrl.getSpec());
            intent.putExtra(
                    CreatorIntentConstants.CREATOR_ENTRY_POINT, SingleWebFeedEntryPoint.MENU);
            intent.putExtra(
                    CreatorIntentConstants.CREATOR_FOLLOWING, mChipView == mFollowingChipView);
            intent.putExtra(CreatorIntentConstants.CREATOR_TAB_ID, mTab.getId());
            mContext.startActivity(intent);
        } catch (Exception e) {
            Log.d(TAG, "Failed to launch CreatorActivity " + e);
        }
    }
}
