/*
 * Copyright (C) 2010 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.email.service;

import android.accounts.AccountManager;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.PeriodicSync;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.CalendarContract;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.text.format.DateUtils;

import androidx.core.app.JobIntentService;

import com.android.email.EmailIntentService;
import com.android.email.Preferences;
import com.android.email.R;
import com.android.email.SecurityPolicy;
import com.android.email.provider.AccountReconciler;
import com.android.emailcommon.Logging;
import com.android.emailcommon.provider.Account;
import com.android.emailcommon.provider.EmailContent;
import com.android.emailcommon.provider.EmailContent.AccountColumns;
import com.android.emailcommon.provider.HostAuth;
import com.android.mail.providers.UIProvider;
import com.android.mail.utils.LogUtils;
import com.android.mail.utils.NotificationActionUtils;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Maps;

import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * The service that really handles broadcast intents on a worker thread.
 *
 * We make it a service, because:
 * <ul>
 *   <li>So that it's less likely for the process to get killed.
 *   <li>Even if it does, the Intent that have started it will be re-delivered by the system,
 *   and we can start the process again.  (Using {@link #setIntentRedelivery}).
 * </ul>
 *
 * This also handles the DeviceAdminReceiver in SecurityPolicy, because it is also
 * a BroadcastReceiver and requires the same processing semantics.
 */
public class EmailBroadcastProcessorService extends JobIntentService {
    public static final int JOB_ID = 200;

    // Action used for BroadcastReceiver entry point
    private static final String ACTION_BROADCAST = "broadcast_receiver";

    // This is a helper used to process DeviceAdminReceiver messages
    private static final String ACTION_DEVICE_POLICY_ADMIN = "com.android.email.devicepolicy";
    private static final String EXTRA_DEVICE_POLICY_ADMIN = "message_code";

    // Action used for EmailUpgradeBroadcastReceiver.
    private static final String ACTION_UPGRADE_BROADCAST = "upgrade_broadcast_receiver";

    public EmailBroadcastProcessorService() {
        super();
    }

    public static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, EmailBroadcastProcessorService.class, JOB_ID, work);
    }

    /**
     * Entry point for {@link EmailBroadcastReceiver}.
     */
    public static void processBroadcastIntent(Context context, Intent broadcastIntent) {
        Intent i = new Intent(context, EmailBroadcastProcessorService.class);
        i.setAction(ACTION_BROADCAST);
        i.putExtra(Intent.EXTRA_INTENT, broadcastIntent);
        EmailBroadcastProcessorService.enqueueWork(context, i);
    }

    public static void processUpgradeBroadcastIntent(final Context context) {
        final Intent i = new Intent(context, EmailBroadcastProcessorService.class);
        i.setAction(ACTION_UPGRADE_BROADCAST);
        EmailBroadcastProcessorService.enqueueWork(context, i);
    }

    /**
     * Entry point for {@link com.android.email.SecurityPolicy.PolicyAdmin}.  These will
     * simply callback to {@link
     * com.android.email.SecurityPolicy#onDeviceAdminReceiverMessage(Context, int)}.
     */
    public static void processDevicePolicyMessage(Context context, int message) {
        Intent i = new Intent(context, EmailBroadcastProcessorService.class);
        i.setAction(ACTION_DEVICE_POLICY_ADMIN);
        i.putExtra(EXTRA_DEVICE_POLICY_ADMIN, message);
        EmailBroadcastProcessorService.enqueueWork(context, i);
    }

    @Override
    protected void onHandleWork(Intent intent) {
        // This method is called on a worker thread.

        // Dispatch from entry point
        final String action = intent.getAction();
        if (ACTION_BROADCAST.equals(action)) {
            final Intent broadcastIntent = intent.getParcelableExtra(Intent.EXTRA_INTENT);
            final String broadcastAction = broadcastIntent.getAction();

            if (Intent.ACTION_BOOT_COMPLETED.equals(broadcastAction)) {
                onBootCompleted();
            } else if (AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION.equals(broadcastAction)) {
                onSystemAccountChanged();
            } else if (Intent.ACTION_LOCALE_CHANGED.equals(broadcastAction) ||
                    UIProvider.ACTION_UPDATE_NOTIFICATION.equals((broadcastAction))) {
                broadcastIntent.setClass(this, EmailIntentService.class);
                startService(broadcastIntent);
            }
        } else if (ACTION_DEVICE_POLICY_ADMIN.equals(action)) {
            int message = intent.getIntExtra(EXTRA_DEVICE_POLICY_ADMIN, -1);
            SecurityPolicy.onDeviceAdminReceiverMessage(this, message);
        } else if (ACTION_UPGRADE_BROADCAST.equals(action)) {
            onAppUpgrade();
        }
    }

    private void disableComponent(final Class<?> klass) {
        getPackageManager().setComponentEnabledSetting(new ComponentName(this, klass),
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
    }

    private boolean isComponentDisabled(final Class<?> klass) {
        return getPackageManager().getComponentEnabledSetting(new ComponentName(this, klass))
                == PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
    }

    private void updateAccountManagerAccountsOfType(final String amAccountType,
            final Map<String, String> protocolMap) {
        final android.accounts.Account[] amAccounts =
                AccountManager.get(this).getAccountsByType(amAccountType);

        for (android.accounts.Account amAccount: amAccounts) {
            EmailServiceUtils.updateAccountManagerType(this, amAccount, protocolMap);
        }
    }

    /**
     * Delete all periodic syncs for an account.
     * @param amAccount The account for which to disable syncs.
     * @param authority The authority for which to disable syncs.
     */
    private static void removePeriodicSyncs(final android.accounts.Account amAccount,
            final String authority) {
        final List<PeriodicSync> syncs =
                ContentResolver.getPeriodicSyncs(amAccount, authority);
        for (final PeriodicSync sync : syncs) {
            ContentResolver.removePeriodicSync(amAccount, authority, sync.extras);
        }
    }

    /**
     * Remove all existing periodic syncs for an account type, and add the necessary syncs.
     * @param amAccountType The account type to handle.
     * @param syncIntervals The map of all account addresses to sync intervals in the DB.
     */
    private void fixPeriodicSyncs(final String amAccountType,
            final Map<String, Integer> syncIntervals) {
        final android.accounts.Account[] amAccounts =
                AccountManager.get(this).getAccountsByType(amAccountType);
        for (android.accounts.Account amAccount : amAccounts) {
            // First delete existing periodic syncs.
            removePeriodicSyncs(amAccount, EmailContent.AUTHORITY);
            removePeriodicSyncs(amAccount, CalendarContract.AUTHORITY);
            removePeriodicSyncs(amAccount, ContactsContract.AUTHORITY);

            // Add back a sync for this account if necessary (i.e. the account has a positive
            // sync interval in the DB). This assumes that the email app requires unique email
            // addresses for each account, which is currently the case.
            final Integer syncInterval = syncIntervals.get(amAccount.name);
            if (syncInterval != null && syncInterval > 0) {
                // Sync interval is stored in minutes in DB, but we want the value in seconds.
                ContentResolver.addPeriodicSync(amAccount, EmailContent.AUTHORITY, Bundle.EMPTY,
                        syncInterval * DateUtils.MINUTE_IN_MILLIS / DateUtils.SECOND_IN_MILLIS);
            }
        }
    }

    /** Projection used for getting sync intervals for all accounts. */
    private static final String[] ACCOUNT_SYNC_INTERVAL_PROJECTION =
            { AccountColumns.EMAIL_ADDRESS, AccountColumns.SYNC_INTERVAL };
    private static final int ACCOUNT_SYNC_INTERVAL_ADDRESS_COLUMN = 0;
    private static final int ACCOUNT_SYNC_INTERVAL_INTERVAL_COLUMN = 1;

    /**
     * Get the sync interval for all accounts, as stored in the DB.
     * @return The map of all sync intervals by account email address.
     */
    private Map<String, Integer> getSyncIntervals() {
        final Cursor c = getContentResolver().query(Account.CONTENT_URI,
                ACCOUNT_SYNC_INTERVAL_PROJECTION, null, null, null);
        if (c != null) {
            final Map<String, Integer> periodicSyncs =
                    Maps.newHashMapWithExpectedSize(c.getCount());
            try {
                while (c.moveToNext()) {
                    periodicSyncs.put(c.getString(ACCOUNT_SYNC_INTERVAL_ADDRESS_COLUMN),
                            c.getInt(ACCOUNT_SYNC_INTERVAL_INTERVAL_COLUMN));
                }
            } finally {
                c.close();
            }
            return periodicSyncs;
        }
        return Collections.emptyMap();
    }

    @VisibleForTesting
    protected static void removeNoopUpgrades(final Map<String, String> protocolMap) {
        final Set<String> keySet = new HashSet<String>(protocolMap.keySet());
        for (final String key : keySet) {
            if (TextUtils.equals(key, protocolMap.get(key))) {
                protocolMap.remove(key);
            }
        }
    }

    private void onAppUpgrade() {
        if (isComponentDisabled(EmailUpgradeBroadcastReceiver.class)) {
            return;
        }
        // When upgrading to a version that changes the protocol strings, we need to essentially
        // rename the account manager type for all existing accounts, so we add new ones and delete
        // the old.
        // We specify the translations in this map. We map from old protocol name to new protocol
        // name, and from protocol name + "_type" to new account manager type name. (Email1 did
        // not use distinct account manager types for POP and IMAP, but Email2 does, hence this
        // weird mapping.)
        final Map<String, String> protocolMap = Maps.newHashMapWithExpectedSize(4);
        protocolMap.put("imap", getString(R.string.protocol_legacy_imap));
        protocolMap.put("pop3", getString(R.string.protocol_pop3));
        removeNoopUpgrades(protocolMap);
        if (!protocolMap.isEmpty()) {
            protocolMap.put("imap_type", getString(R.string.account_manager_type_legacy_imap));
            protocolMap.put("pop3_type", getString(R.string.account_manager_type_pop3));
            updateAccountManagerAccountsOfType("com.android.email", protocolMap);
        }

        protocolMap.clear();
        protocolMap.put("eas", getString(R.string.protocol_eas));
        removeNoopUpgrades(protocolMap);
        if (!protocolMap.isEmpty()) {
            protocolMap.put("eas_type", getString(R.string.account_manager_type_exchange));
            updateAccountManagerAccountsOfType("com.android.exchange", protocolMap);
        }

        // Disable the old authenticators.
        disableComponent(LegacyEmailAuthenticatorService.class);
        disableComponent(LegacyEasAuthenticatorService.class);

        // Fix periodic syncs.
        final Map<String, Integer> syncIntervals = getSyncIntervals();
        for (final EmailServiceUtils.EmailServiceInfo service
                : EmailServiceUtils.getServiceInfoList(this)) {
            fixPeriodicSyncs(service.accountType, syncIntervals);
        }

        // Disable the upgrade broadcast receiver now that we're fully upgraded.
        disableComponent(EmailUpgradeBroadcastReceiver.class);
    }

    /**
     * Handles {@link Intent#ACTION_BOOT_COMPLETED}.  Called on a worker thread.
     */
    private void onBootCompleted() {
        performOneTimeInitialization();
        reconcileAndStartServices();
    }

    private void reconcileAndStartServices() {
        /**
         *  We can get here before the ACTION_UPGRADE_BROADCAST is received, so make sure the
         *  accounts are converted otherwise terrible, horrible things will happen.
         */
        onAppUpgrade();
        // Reconcile accounts
        AccountReconciler.reconcileAccounts(this);
        // Starts remote services, if any
        EmailServiceUtils.startRemoteServices(this);
    }

    private void performOneTimeInitialization() {
        final Preferences pref = Preferences.getPreferences(this);
        int progress = pref.getOneTimeInitializationProgress();
        final int initialProgress = progress;

        if (progress < 1) {
            LogUtils.i(Logging.LOG_TAG, "Onetime initialization: 1");
            progress = 1;
            EmailServiceUtils.enableExchangeComponent(this);
        }

        if (progress < 2) {
            LogUtils.i(Logging.LOG_TAG, "Onetime initialization: 2");
            progress = 2;
            setImapDeletePolicy(this);
        }

        // Add your initialization steps here.
        // Use "progress" to skip the initializations that's already done before.
        // Using this preference also makes it safe when a user skips an upgrade.  (i.e. upgrading
        // version N to version N+2)

        if (progress != initialProgress) {
            pref.setOneTimeInitializationProgress(progress);
            LogUtils.i(Logging.LOG_TAG, "Onetime initialization: completed.");
        }
    }

    /**
     * Sets the delete policy to the correct value for all IMAP accounts. This will have no
     * effect on either EAS or POP3 accounts.
     */
    /*package*/ static void setImapDeletePolicy(Context context) {
        ContentResolver resolver = context.getContentResolver();
        Cursor c = resolver.query(Account.CONTENT_URI, Account.CONTENT_PROJECTION,
                null, null, null);
        try {
            while (c.moveToNext()) {
                long recvAuthKey = c.getLong(Account.CONTENT_HOST_AUTH_KEY_RECV_COLUMN);
                HostAuth recvAuth = HostAuth.restoreHostAuthWithId(context, recvAuthKey);
                String legacyImapProtocol = context.getString(R.string.protocol_legacy_imap);
                if (legacyImapProtocol.equals(recvAuth.mProtocol)) {
                    int flags = c.getInt(Account.CONTENT_FLAGS_COLUMN);
                    flags &= ~Account.FLAGS_DELETE_POLICY_MASK;
                    flags |= Account.DELETE_POLICY_ON_DELETE << Account.FLAGS_DELETE_POLICY_SHIFT;
                    ContentValues cv = new ContentValues();
                    cv.put(AccountColumns.FLAGS, flags);
                    long accountId = c.getLong(Account.CONTENT_ID_COLUMN);
                    Uri uri = ContentUris.withAppendedId(Account.CONTENT_URI, accountId);
                    resolver.update(uri, cv, null, null);
                }
            }
        } finally {
            c.close();
        }
    }

    private void onSystemAccountChanged() {
        LogUtils.i(Logging.LOG_TAG, "System accounts updated.");
        reconcileAndStartServices();
        // Resend all notifications, so that there is no notification that points to a removed
        // account.
        NotificationActionUtils.resendNotifications(getApplicationContext(),
                null /* all accounts */, null /* all folders */);
    }
}
