// Copyright 2020 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.password_check.helper;

import android.content.Context;
import android.graphics.Bitmap;

import androidx.annotation.Nullable;
import androidx.core.util.Pair;

import org.chromium.base.Callback;
import org.chromium.chrome.browser.password_check.CompromisedCredential;
import org.chromium.chrome.browser.password_check.R;
import org.chromium.components.favicon.IconType;
import org.chromium.components.favicon.LargeIconBridge;
import org.chromium.url.GURL;

/**
 * Helper used to fetch or create an appropriate icon for a compromised credential.
 */
public class PasswordCheckIconHelper {
    /**
     * Data object containing all data required to set an icon or construct a fallback.
     */
    public static class FaviconOrFallback {
        public final String mUrlOrAppName;
        public final @Nullable Bitmap mIcon;
        public final int mFallbackColor;
        public final boolean mIsFallbackColorDefault;
        public final int mIconType;
        public final int mIconSize;

        FaviconOrFallback(String urlOrAppName, @Nullable Bitmap icon, int fallbackColor,
                boolean isFallbackColorDefault, int iconType, int iconSize) {
            mUrlOrAppName = urlOrAppName;
            mIcon = icon;
            mFallbackColor = fallbackColor;
            mIsFallbackColorDefault = isFallbackColorDefault;
            mIconType = iconType;
            mIconSize = iconSize;
        }
    }

    private final LargeIconBridge mLargeIconBridge;
    private final int mDesiredIconSize;

    public PasswordCheckIconHelper(LargeIconBridge largeIconBridge, int desiredIconSize) {
        mLargeIconBridge = largeIconBridge;
        mDesiredIconSize = desiredIconSize;
    }

    public void getLargeIcon(
            CompromisedCredential credential, Callback<FaviconOrFallback> iconCallback) {
        final Pair<GURL, String> originAndFallback = getIconOriginAndFallback(credential);
        if (!originAndFallback.first.isValid()) {
            iconCallback.onResult(new FaviconOrFallback(
                    originAndFallback.second, null, 0, true, IconType.INVALID, mDesiredIconSize));
            return; // Abort because an invalid icon URLs will crash Chrome!
        }
        mLargeIconBridge.getLargeIconForUrl(originAndFallback.first, mDesiredIconSize,
                (icon, fallbackColor, hasDefaultColor, type) -> {
                    iconCallback.onResult(new FaviconOrFallback(originAndFallback.second, icon,
                            fallbackColor, hasDefaultColor, type, mDesiredIconSize));
                });
    }

    /**
     * @param faviconOrFallbackData A {@link FaviconOrFallback} containing color or fallback hints.
     * @param context A {@link Context} object used to load default colors if necessary.
     * @return A color (non-resource value) to use for monogram icons.
     */
    public static int getIconColor(
            PasswordCheckIconHelper.FaviconOrFallback faviconOrFallbackData, Context context) {
        return faviconOrFallbackData.mIsFallbackColorDefault
                ? context.getColor(R.color.default_favicon_background_color)
                : faviconOrFallbackData.mFallbackColor;
    }

    /**
     * Determines which origin to use for retrieving a favicon.
     * @param credential A {@link CompromisedCredential}.
     * @return A pair with (potentially invalid) icon origin and a fallback URL for monograms.
     */
    private static Pair<GURL, String> getIconOriginAndFallback(CompromisedCredential credential) {
        if (!credential.getAssociatedApp().isEmpty()) {
            return getIconOriginAndFallbackForApp(credential);
        }

        // Ideally, the sign-on realm is valid and has an adjacent, valid icon.
        GURL iconOrigin = new GURL(credential.getSignonRealm());
        String fallbackUrl = credential.getSignonRealm();
        if (!iconOrigin.isValid()) {
            // If the sign-on realm isn't valid, try the change URL instead.
            iconOrigin = new GURL(credential.getPasswordChangeUrl());
            fallbackUrl = credential.getPasswordChangeUrl();
        }
        if (!iconOrigin.isValid()) {
            // If neither URL is valid, try the display origin as a last, very weak hope.
            iconOrigin = credential.getAssociatedUrl();
            fallbackUrl = credential.getDisplayOrigin();
        }
        return new Pair<>(iconOrigin, fallbackUrl);
    }

    private static Pair<GURL, String> getIconOriginAndFallbackForApp(
            CompromisedCredential credential) {
        return new Pair<>(new GURL(credential.getDisplayOrigin()), credential.getDisplayOrigin());
    }
}
