/*
 * Copyright (C) 2019 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.car.settings.datausage;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.icu.text.MeasureFormat;
import android.icu.util.MeasureUnit;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.NumberPicker;

import androidx.annotation.IntegerRes;
import androidx.annotation.VisibleForTesting;

import com.android.car.settings.R;
import com.android.car.ui.preference.CarUiDialogFragment;

/** Dialog that is used to pick the data usage warning/limit threshold bytes. */
public class UsageBytesThresholdPickerDialog extends CarUiDialogFragment {

    /** Tag used to identify dialog in {@link androidx.fragment.app.FragmentManager}. */
    public static final String TAG = "UsageBytesThresholdPickerDialog";
    private static final String ARG_DIALOG_TITLE_RES = "arg_dialog_title_res";
    private static final String ARG_CURRENT_THRESHOLD = "arg_current_threshold";
    private static final float MB_GB_SUFFIX_THRESHOLD = 1.5f;

    @VisibleForTesting
    static final long MIB_IN_BYTES = 1024 * 1024;
    @VisibleForTesting
    static final long GIB_IN_BYTES = MIB_IN_BYTES * 1024;
    @VisibleForTesting
    static final long MAX_DATA_LIMIT_BYTES = 50000 * GIB_IN_BYTES;

    // Number pickers can be used to pick strings as well.
    private NumberPicker mBytesUnits;
    private View mUpArrow;
    private View mDownArrow;
    private EditText mThresholdEditor;
    private BytesThresholdPickedListener mBytesThresholdPickedListener;
    private long mCurrentThreshold;

    /**
     * Creates a new instance of the {@link UsageBytesThresholdPickerDialog} with the
     * {@code currentThreshold} represented with the best units available.
     */
    public static UsageBytesThresholdPickerDialog newInstance(@IntegerRes int dialogTitle,
            long currentThreshold) {
        UsageBytesThresholdPickerDialog dialog = new UsageBytesThresholdPickerDialog();
        Bundle args = new Bundle();
        args.putInt(ARG_DIALOG_TITLE_RES, dialogTitle);
        args.putLong(ARG_CURRENT_THRESHOLD, currentThreshold);
        dialog.setArguments(args);
        return dialog;
    }

    /** Sets a {@link BytesThresholdPickedListener}. */
    public void setBytesThresholdPickedListener(
            BytesThresholdPickedListener bytesThresholdPickedListener) {
        mBytesThresholdPickedListener = bytesThresholdPickedListener;
    }

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getContext());

        // Use builder context to keep consistent theme.
        LayoutInflater inflater = LayoutInflater.from(builder.getContext());
        View view = inflater.inflate(R.layout.usage_bytes_threshold_picker,
                /* root= */ null, /* attachToRoot= */ false);

        mCurrentThreshold = getArguments().getLong(ARG_CURRENT_THRESHOLD);
        if (mCurrentThreshold < 0) {
            mCurrentThreshold = 0;
        }

        MeasureFormat formatter = MeasureFormat.getInstance(
                getContext().getResources().getConfiguration().locale,
                MeasureFormat.FormatWidth.SHORT);
        String[] units = new String[] {
            formatter.getUnitDisplayName(MeasureUnit.MEGABYTE),
            formatter.getUnitDisplayName(MeasureUnit.GIGABYTE)
        };
        mBytesUnits = view.findViewById(R.id.bytes_units);
        mBytesUnits.setMinValue(0);
        mBytesUnits.setMaxValue(units.length - 1);
        mBytesUnits.setDisplayedValues(units);

        mThresholdEditor = view.findViewById(R.id.bytes_threshold);

        mUpArrow = view.findViewById(R.id.up_arrow_container);
        mUpArrow.setOnClickListener(v -> mBytesUnits.setValue(mBytesUnits.getValue() - 1));

        mDownArrow = view.findViewById(R.id.down_arrow_container);
        mDownArrow.setOnClickListener(v -> mBytesUnits.setValue(mBytesUnits.getValue() + 1));

        updateCurrentView(mCurrentThreshold);

        return builder
                .setTitle(getArguments().getInt(ARG_DIALOG_TITLE_RES))
                .setView(view)
                .setPositiveButton(R.string.usage_bytes_threshold_picker_positive_button,
                        /* onClickListener= */ this)
                .create();
    }

    @Override
    protected void onDialogClosed(boolean positiveResult) {
    }

    @Override
    public void onClick(DialogInterface dialog, int which) {
        if (which == DialogInterface.BUTTON_POSITIVE) {
            long newThreshold = getCurrentThreshold();
            if (mBytesThresholdPickedListener != null
                    && mCurrentThreshold != newThreshold) {
                mBytesThresholdPickedListener.onThresholdPicked(newThreshold);
            }
        }
    }

    /** Gets the threshold currently represented by this {@link UsageBytesThresholdPickerDialog}. */
    public long getCurrentThreshold() {
        String bytesString = mThresholdEditor.getText().toString();
        if (bytesString.isEmpty() || bytesString.equals(".")) {
            bytesString = "0";
        }

        long bytes = (long) (Float.valueOf(bytesString) * (mBytesUnits.getValue() == 0
                ? MIB_IN_BYTES : GIB_IN_BYTES));

        // To fix the overflow problem.
        long correctedBytes = Math.min(MAX_DATA_LIMIT_BYTES, bytes);

        return correctedBytes;
    }

    @VisibleForTesting
    void setThresholdEditor(long threshold) {
        updateCurrentView(threshold);
    }

    private void updateCurrentView(long threshold) {
        String bytesText;
        if (threshold > MB_GB_SUFFIX_THRESHOLD * GIB_IN_BYTES) {
            bytesText = formatText(threshold / (float) GIB_IN_BYTES);
            mBytesUnits.setValue(1);
        } else {
            bytesText = formatText(threshold / (float) MIB_IN_BYTES);
            mBytesUnits.setValue(0);
        }
        mThresholdEditor.setText(bytesText);
        mThresholdEditor.setSelection(0, bytesText.length());
    }

    private String formatText(float v) {
        v = Math.round(v * 100) / 100f;
        return String.valueOf(v);
    }

    /** A listener that is called when a date is selected. */
    public interface BytesThresholdPickedListener {
        /** A method that determines how to process the selected day of month. */
        void onThresholdPicked(long numBytes);
    }
}