/*
 * Copyright (C) 2018 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.settingslib.notification;

import android.app.ActivityManager;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.provider.Settings;
import android.service.notification.Condition;
import android.service.notification.ZenModeConfig;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.ScrollView;
import android.widget.TextView;

import androidx.annotation.VisibleForTesting;
import androidx.appcompat.app.AlertDialog;

import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto;
import com.android.internal.policy.PhoneWindow;
import com.android.settingslib.R;

import java.util.Arrays;

public class ZenDurationDialog {
    private static final int[] MINUTE_BUCKETS = ZenModeConfig.MINUTE_BUCKETS;
    @VisibleForTesting protected static final int MIN_BUCKET_MINUTES = MINUTE_BUCKETS[0];
    @VisibleForTesting protected static final int MAX_BUCKET_MINUTES =
            MINUTE_BUCKETS[MINUTE_BUCKETS.length - 1];
    private static final int DEFAULT_BUCKET_INDEX = Arrays.binarySearch(MINUTE_BUCKETS, 60);
    @VisibleForTesting protected int mBucketIndex = -1;

    @VisibleForTesting protected static final int FOREVER_CONDITION_INDEX = 0;
    @VisibleForTesting protected static final int COUNTDOWN_CONDITION_INDEX = 1;
    @VisibleForTesting protected static final int ALWAYS_ASK_CONDITION_INDEX = 2;

    @VisibleForTesting protected Context mContext;
    @VisibleForTesting protected LinearLayout mZenRadioGroupContent;
    private RadioGroup mZenRadioGroup;
    private int MAX_MANUAL_DND_OPTIONS = 3;

    @VisibleForTesting protected LayoutInflater mLayoutInflater;

    public ZenDurationDialog(Context context) {
        mContext = context;
    }

    public Dialog createDialog() {
        final AlertDialog.Builder builder = new AlertDialog.Builder(mContext);
        setupDialog(builder);
        return builder.create();
    }

    public void setupDialog(AlertDialog.Builder builder) {
        int zenDuration = Settings.Secure.getInt(
                mContext.getContentResolver(), Settings.Secure.ZEN_DURATION,
                Settings.Secure.ZEN_DURATION_FOREVER);

        builder.setTitle(R.string.zen_mode_duration_settings_title)
                .setNegativeButton(R.string.cancel, null)
                .setPositiveButton(R.string.okay,
                        new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                updateZenDuration(zenDuration);
                            }
                        });

        View contentView = getContentView();
        setupRadioButtons(zenDuration);
        builder.setView(contentView);
    }

    @VisibleForTesting
    protected void updateZenDuration(int currZenDuration) {
        final int checkedRadioButtonId = mZenRadioGroup.getCheckedRadioButtonId();

        int newZenDuration = Settings.Secure.getInt(
                mContext.getContentResolver(), Settings.Secure.ZEN_DURATION,
                Settings.Secure.ZEN_DURATION_FOREVER);
        switch (checkedRadioButtonId) {
            case FOREVER_CONDITION_INDEX:
                newZenDuration = Settings.Secure.ZEN_DURATION_FOREVER;
                MetricsLogger.action(mContext,
                        MetricsProto.MetricsEvent.
                                NOTIFICATION_ZEN_MODE_DURATION_FOREVER);
                break;
            case COUNTDOWN_CONDITION_INDEX:
                ConditionTag tag = getConditionTagAt(checkedRadioButtonId);
                newZenDuration = tag.countdownZenDuration;
                MetricsLogger.action(mContext,
                        MetricsProto.MetricsEvent.
                                NOTIFICATION_ZEN_MODE_DURATION_TIME,
                        newZenDuration);
                break;
            case ALWAYS_ASK_CONDITION_INDEX:
                newZenDuration = Settings.Secure.ZEN_DURATION_PROMPT;
                MetricsLogger.action(mContext,
                        MetricsProto.MetricsEvent.
                                NOTIFICATION_ZEN_MODE_DURATION_PROMPT);
                break;
        }

        if (currZenDuration != newZenDuration) {
            Settings.Secure.putInt(mContext.getContentResolver(),
                    Settings.Secure.ZEN_DURATION, newZenDuration);
        }
    }

    @VisibleForTesting
    protected View getContentView() {
        if (mLayoutInflater == null) {
            mLayoutInflater = new PhoneWindow(mContext).getLayoutInflater();
        }
        View contentView = mLayoutInflater.inflate(R.layout.zen_mode_duration_dialog,
                null);
        ScrollView container = (ScrollView) contentView.findViewById(R.id.zen_duration_container);

        mZenRadioGroup = container.findViewById(R.id.zen_radio_buttons);
        mZenRadioGroupContent = container.findViewById(R.id.zen_radio_buttons_content);

        for (int i = 0; i < MAX_MANUAL_DND_OPTIONS; i++) {
            final View radioButton = mLayoutInflater.inflate(R.layout.zen_mode_radio_button,
                    mZenRadioGroup, false);
            mZenRadioGroup.addView(radioButton);
            radioButton.setId(i);

            final View radioButtonContent = mLayoutInflater.inflate(R.layout.zen_mode_condition,
                    mZenRadioGroupContent, false);
            radioButtonContent.setId(i + MAX_MANUAL_DND_OPTIONS);
            mZenRadioGroupContent.addView(radioButtonContent);
        }

        return contentView;
    }

    @VisibleForTesting
    protected void setupRadioButtons(int zenDuration) {
        int checkedIndex = ALWAYS_ASK_CONDITION_INDEX;
        if (zenDuration == 0) {
            checkedIndex = FOREVER_CONDITION_INDEX;
        } else if (zenDuration > 0) {
            checkedIndex = COUNTDOWN_CONDITION_INDEX;
        }

        bindTag(zenDuration, mZenRadioGroupContent.getChildAt(FOREVER_CONDITION_INDEX),
                FOREVER_CONDITION_INDEX);
        bindTag(zenDuration, mZenRadioGroupContent.getChildAt(COUNTDOWN_CONDITION_INDEX),
                COUNTDOWN_CONDITION_INDEX);
        bindTag(zenDuration, mZenRadioGroupContent.getChildAt(ALWAYS_ASK_CONDITION_INDEX),
                ALWAYS_ASK_CONDITION_INDEX);
        getConditionTagAt(checkedIndex).rb.setChecked(true);
    }

    private void bindTag(final int currZenDuration, final View row, final int rowIndex) {
        final ConditionTag tag = row.getTag() != null ? (ConditionTag) row.getTag() :
                new ConditionTag();
        row.setTag(tag);

        if (tag.rb == null) {
            tag.rb = (RadioButton) mZenRadioGroup.getChildAt(rowIndex);
        }

        // if duration is set to forever or always prompt, then countdown time defaults to 1 hour
        if (currZenDuration <= 0) {
            tag.countdownZenDuration = MINUTE_BUCKETS[DEFAULT_BUCKET_INDEX];
        } else {
            tag.countdownZenDuration = currZenDuration;
        }

        tag.rb.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    tag.rb.setChecked(true);
                }
            }
        });

        updateUi(tag, row, rowIndex);
    }

    @VisibleForTesting
    protected ConditionTag getConditionTagAt(int index) {
        return (ConditionTag) mZenRadioGroupContent.getChildAt(index).getTag();
    }


    private void setupUi(ConditionTag tag, View row) {
        if (tag.lines == null) {
            tag.lines = row.findViewById(android.R.id.content);
        }

        if (tag.line1 == null) {
            tag.line1 = (TextView) row.findViewById(android.R.id.text1);
        }

        // text2 is not used in zen duration dialog
        row.findViewById(android.R.id.text2).setVisibility(View.GONE);

        tag.lines.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                tag.rb.setChecked(true);
            }
        });
    }

    private void updateButtons(ConditionTag tag, View row, int rowIndex) {
        // minus button
        final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1);
        button1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onClickTimeButton(row, tag, false /*down*/, rowIndex);
            }
        });

        // plus button
        final ImageView button2 = (ImageView) row.findViewById(android.R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onClickTimeButton(row, tag, true /*up*/, rowIndex);
            }
        });

        final long time = tag.countdownZenDuration;
        if (rowIndex == COUNTDOWN_CONDITION_INDEX) {
            button1.setVisibility(View.VISIBLE);
            button2.setVisibility(View.VISIBLE);

            button1.setEnabled(time > MIN_BUCKET_MINUTES);
            button2.setEnabled(tag.countdownZenDuration != MAX_BUCKET_MINUTES);

            button1.setAlpha(button1.isEnabled() ? 1f : .5f);
            button2.setAlpha(button2.isEnabled() ? 1f : .5f);
        } else {
            button1.setVisibility(View.GONE);
            button2.setVisibility(View.GONE);
        }
    }

    @VisibleForTesting
    protected void updateUi(ConditionTag tag, View row, int rowIndex) {
        if (tag.lines == null) {
            setupUi(tag, row);
        }

        updateButtons(tag, row, rowIndex);

        String radioContentText = "";
        switch (rowIndex) {
            case FOREVER_CONDITION_INDEX:
                radioContentText = mContext.getString(R.string.zen_mode_forever);
                break;
            case COUNTDOWN_CONDITION_INDEX:
                Condition condition = ZenModeConfig.toTimeCondition(mContext,
                        tag.countdownZenDuration, ActivityManager.getCurrentUser(), false);
                radioContentText = condition.line1;
                break;
            case ALWAYS_ASK_CONDITION_INDEX:
                radioContentText = mContext.getString(
                        R.string.zen_mode_duration_always_prompt_title);
                break;
        }

        tag.line1.setText(radioContentText);
    }

    @VisibleForTesting
    protected void onClickTimeButton(View row, ConditionTag tag, boolean up, int rowId) {
        int newDndTimeDuration = -1;
        final int N = MINUTE_BUCKETS.length;
        if (mBucketIndex == -1) {
            // not on a known index, search for the next or prev bucket by time
            final long time = tag.countdownZenDuration;
            for (int i = 0; i < N; i++) {
                int j = up ? i : N - 1 - i;
                final int bucketMinutes = MINUTE_BUCKETS[j];
                if (up && bucketMinutes > time || !up && bucketMinutes < time) {
                    mBucketIndex = j;
                    newDndTimeDuration = bucketMinutes;
                    break;
                }
            }
            if (newDndTimeDuration == -1) {
                mBucketIndex = DEFAULT_BUCKET_INDEX;
                newDndTimeDuration = MINUTE_BUCKETS[mBucketIndex];
            }
        } else {
            // on a known index, simply increment or decrement
            mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1)));
            newDndTimeDuration = MINUTE_BUCKETS[mBucketIndex];
        }
        tag.countdownZenDuration = newDndTimeDuration;
        bindTag(newDndTimeDuration, row, rowId);
        tag.rb.setChecked(true);
    }

    // used as the view tag on condition rows
    @VisibleForTesting
    protected static class ConditionTag {
        public RadioButton rb;
        public View lines;
        public TextView line1;
        public int countdownZenDuration; // only important for countdown radio button
    }
}
