/*
 * Copyright (C) 2022 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.localepicker;

import android.app.FragmentTransaction;
import android.app.LocaleManager;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.LocaleList;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ListView;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;

import com.android.internal.app.LocalePickerWithRegion;
import com.android.internal.app.LocaleStore;
import com.android.settings.R;
import com.android.settings.applications.AppLocaleUtil;
import com.android.settings.applications.appinfo.AppLocaleDetails;
import com.android.settings.core.SettingsBaseActivity;

import java.util.Locale;

public class AppLocalePickerActivity extends SettingsBaseActivity
        implements LocalePickerWithRegion.LocaleSelectedListener, MenuItem.OnActionExpandListener {
    private static final String TAG = AppLocalePickerActivity.class.getSimpleName();
    static final String EXTRA_APP_LOCALE = "app_locale";
    private static final String PROP_SYSTEM_LOCALE_SUGGESTION = "android.system.locale.suggestion";
    private static final boolean ENABLED = false;

    private String mPackageName;
    private LocalePickerWithRegion mLocalePickerWithRegion;
    private AppLocaleDetails mAppLocaleDetails;
    private View mAppLocaleDetailContainer;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Uri data = getIntent().getData();
        if (data == null) {
            Log.d(TAG, "There is no uri data.");
            finish();
            return;
        }
        mPackageName = data.getSchemeSpecificPart();
        if (TextUtils.isEmpty(mPackageName)) {
            Log.d(TAG, "There is no package name.");
            finish();
            return;
        }

        if (!canDisplayLocaleUi()) {
            Log.w(TAG, "Not allow to display Locale Settings UI.");
            finish();
            return;
        }

        setTitle(R.string.app_locale_picker_title);
        getActionBar().setDisplayHomeAsUpEnabled(true);

        mLocalePickerWithRegion = LocalePickerWithRegion.createLanguagePicker(
                this,
                this,
                false /* translate only */,
                null,
                mPackageName,
                this);
        mAppLocaleDetails = AppLocaleDetails.newInstance(mPackageName, getUserId());
        mAppLocaleDetailContainer = launchAppLocaleDetailsPage();
        // Launch Locale picker part.
        launchLocalePickerPage();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home) {
            super.onBackPressed();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onLocaleSelected(LocaleStore.LocaleInfo localeInfo) {
        if (localeInfo == null || localeInfo.getLocale() == null || localeInfo.isSystemLocale()) {
            setAppDefaultLocale("");
        } else {
            setAppDefaultLocale(localeInfo.getLocale().toLanguageTag());
            broadcastAppLocaleChange(localeInfo);
        }
        finish();
    }

    @Override
    public boolean onMenuItemActionCollapse(MenuItem item) {
        mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/);
        return true;
    }

    @Override
    public boolean onMenuItemActionExpand(MenuItem item) {
        mAppBarLayout.setExpanded(false /*expanded*/, false /*animate*/);
        return true;
    }

    /** Sets the app's locale to the supplied language tag */
    private void setAppDefaultLocale(String languageTag) {
        Log.d(TAG, "setAppDefaultLocale: " + languageTag);
        LocaleManager localeManager = getSystemService(LocaleManager.class);
        if (localeManager == null) {
            Log.w(TAG, "LocaleManager is null, cannot set default app locale");
            return;
        }
        localeManager.setApplicationLocales(mPackageName, LocaleList.forLanguageTags(languageTag));
    }

    private void broadcastAppLocaleChange(LocaleStore.LocaleInfo localeInfo) {
        if (!SystemProperties.getBoolean(PROP_SYSTEM_LOCALE_SUGGESTION, ENABLED)) {
            return;
        }
        String languageTag = localeInfo.getLocale().toLanguageTag();
        if (isInSystemLocale(languageTag) || localeInfo.isAppCurrentLocale()) {
            return;
        }
        String intentAction = getString(R.string.config_app_locale_intent_action);
        if (!TextUtils.isEmpty(intentAction)) {
            try {
                PackageManager packageManager = getPackageManager();
                ApplicationInfo info = packageManager.getApplicationInfo(mPackageName,
                        PackageManager.GET_META_DATA);
                Intent intent = new Intent(intentAction)
                        .putExtra(Intent.EXTRA_UID, info.uid)
                        .putExtra(EXTRA_APP_LOCALE, languageTag);
                if (intent.resolveActivity(packageManager) != null) {
                    mStartForResult.launch(intent);
                }
            } catch (PackageManager.NameNotFoundException e) {
                Log.e(TAG, "Unable to find info for package: " + mPackageName);
            }
        }
    }

    // Invoke startActivityFroResult so that the calling package can be shared via the intent.
    private ActivityResultLauncher<Intent> mStartForResult = registerForActivityResult(
            new ActivityResultContracts.StartActivityForResult(),
            result -> {
            }
    );

    /**
     * Checks if the localeTag is in the system locale. Since in the current design, the system
     * language list would not show two locales with the same language and region but different
     * numbering system. So, during the comparison, the extension has to be stripped.
     *
     * @param languageTag A language tag
     * @return true if the locale is in the system locale. Otherwise, false.
     */
    private static boolean isInSystemLocale(String languageTag) {
        LocaleList systemLocales = LocaleList.getDefault();
        Locale locale = Locale.forLanguageTag(languageTag).stripExtensions();
        for (int i = 0; i < systemLocales.size(); i++) {
            if (locale.equals(systemLocales.get(i).stripExtensions())) {
                return true;
            }
        }
        return false;
    }

    private View launchAppLocaleDetailsPage() {
        FrameLayout appLocaleDetailsContainer = new FrameLayout(this);
        appLocaleDetailsContainer.setId(R.id.layout_app_locale_details);
        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.layout_app_locale_details, mAppLocaleDetails)
                .commit();
        return appLocaleDetailsContainer;
    }

    private void launchLocalePickerPage() {
        // LocalePickerWithRegion use android.app.ListFragment. Thus, it can not use
        // getSupportFragmentManager() to add this into container.
        android.app.FragmentManager fragmentManager = getFragmentManager();
        fragmentManager.registerFragmentLifecycleCallbacks(
                new android.app.FragmentManager.FragmentLifecycleCallbacks() {
                    @Override
                    public void onFragmentViewCreated(
                            android.app.FragmentManager fm,
                            android.app.Fragment f, View v, Bundle s) {
                        super.onFragmentViewCreated(fm, f, v, s);
                        ListView listView = (ListView) v.findViewById(android.R.id.list);
                        if (listView != null) {
                            listView.addHeaderView(mAppLocaleDetailContainer);
                        }
                    }
                }, true);
        fragmentManager.beginTransaction()
                .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
                .replace(R.id.content_frame, mLocalePickerWithRegion)
                .commit();
    }

    private boolean canDisplayLocaleUi() {
        try {
            PackageManager packageManager = getPackageManager();
            return AppLocaleUtil.canDisplayLocaleUi(this,
                    packageManager.getApplicationInfo(mPackageName, 0),
                    packageManager.queryIntentActivities(AppLocaleUtil.LAUNCHER_ENTRY_INTENT,
                            PackageManager.GET_META_DATA));
        } catch (PackageManager.NameNotFoundException e) {
            Log.e(TAG, "Unable to find info for package: " + mPackageName);
        }

        return false;
    }
}
