/*
 * Copyright (c) 2018, Nordic Semiconductor
 *
 * SPDX-License-Identifier: Apache-2.0
 */

package io.runtime.mcumgr.sample.fragment.mcumgr;

import android.animation.LayoutTransition;
import android.graphics.Typeface;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.text.style.StyleSpan;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView;

import javax.inject.Inject;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import butterknife.BindView;
import butterknife.ButterKnife;
import io.runtime.mcumgr.response.img.McuMgrImageStateResponse;
import io.runtime.mcumgr.sample.R;
import io.runtime.mcumgr.sample.di.Injectable;
import io.runtime.mcumgr.sample.dialog.HelpDialogFragment;
import io.runtime.mcumgr.sample.utils.StringUtils;
import io.runtime.mcumgr.sample.viewmodel.mcumgr.ImageControlViewModel;
import io.runtime.mcumgr.sample.viewmodel.mcumgr.McuMgrViewModelFactory;

public class ImageControlFragment extends Fragment implements Injectable, Toolbar.OnMenuItemClickListener {

    @Inject
    McuMgrViewModelFactory mViewModelFactory;

    @BindView(R.id.image_control_value)
    TextView mValue;
    @BindView(R.id.image_control_error)
    TextView mError;
    @BindView(R.id.action_read)
    Button mReadAction;
    @BindView(R.id.action_test)
    Button mTestAction;
    @BindView(R.id.action_confirm)
    Button mConfirmAction;
    @BindView(R.id.action_erase)
    Button mEraseAction;

    private ImageControlViewModel mViewModel;

    @Override
    public void onCreate(@Nullable final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mViewModel = new ViewModelProvider(this, mViewModelFactory)
                .get(ImageControlViewModel.class);
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull final LayoutInflater inflater,
                             @Nullable final ViewGroup container,
                             @Nullable final Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_card_image_control, container, false);
    }

    @Override
    public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        ButterKnife.bind(this, view);

        final Toolbar toolbar = view.findViewById(R.id.toolbar);
        toolbar.inflateMenu(R.menu.help);
        toolbar.setOnMenuItemClickListener(this);

        // This makes the layout animate when the TextView value changes.
        // By default it animates only on hiding./showing views.
        // The view must have android:animateLayoutChanges(true) attribute set in the XML.
        ((ViewGroup) view).getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
    }

    @Override
    public boolean onMenuItemClick(final MenuItem item) {
        switch (item.getItemId()) {
            case R.id.action_help:
                final DialogFragment dialog = HelpDialogFragment.getInstance(
                        R.string.image_control_dialog_help_title,
                        R.string.image_control_dialog_help_message);
                dialog.show(getChildFragmentManager(), null);
                return true;
        }
        return false;
    }

    @Override
    public void onActivityCreated(@Nullable final Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        mViewModel.getResponse().observe(getViewLifecycleOwner(), this::printImageSlotInfo);
        mViewModel.getError().observe(getViewLifecycleOwner(), this::printError);
        mViewModel.getTestOperationAvailability().observe(getViewLifecycleOwner(),
                enabled -> mTestAction.setEnabled(enabled));
        mViewModel.getConfirmOperationAvailability().observe(getViewLifecycleOwner(),
                enabled -> mConfirmAction.setEnabled(enabled));
        mViewModel.getEraseOperationAvailability().observe(getViewLifecycleOwner(),
                enabled -> mEraseAction.setEnabled(enabled));
        mViewModel.getBusyState().observe(getViewLifecycleOwner(), busy -> {
            if (busy) {
                mReadAction.setEnabled(false);
                mTestAction.setEnabled(false);
                mConfirmAction.setEnabled(false);
                mEraseAction.setEnabled(false);
            } else {
                mReadAction.setEnabled(true);
                // Other actions will be optionally enabled by other observers
            }
        });
        mReadAction.setOnClickListener(v -> mViewModel.read());
        mTestAction.setOnClickListener(v -> mViewModel.test());
        mConfirmAction.setOnClickListener(v -> mViewModel.confirm());
        mEraseAction.setOnClickListener(v -> mViewModel.erase());
    }

    private void printImageSlotInfo(@Nullable final McuMgrImageStateResponse response) {
        if (response != null) {
            final SpannableStringBuilder builder = new SpannableStringBuilder();
            builder.append(getString(R.string.image_control_split_status, response.splitStatus));
            builder.setSpan(new StyleSpan(Typeface.BOLD),
                    0, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
            for (final McuMgrImageStateResponse.ImageSlot slot : response.images) {
                final int index = builder.length();
                builder.append("\n");
                builder.append(getString(R.string.image_control_slot,
                        slot.slot, slot.version, StringUtils.toHex(slot.hash),
                        slot.bootable, slot.pending, slot.confirmed,
                        slot.active, slot.permanent));
                builder.setSpan(new StyleSpan(Typeface.BOLD),
                        index, index + 8, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
            }
            mValue.setText(builder);
            mError.setVisibility(View.GONE);
        } else {
            mValue.setText(null);
        }
    }

    private void printError(@Nullable final String error) {
        if (error != null) {
            final SpannableString spannable = new SpannableString(error);
            spannable.setSpan(new ForegroundColorSpan(
                            ContextCompat.getColor(requireContext(), R.color.colorError)),
                    0, error.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
            spannable.setSpan(new StyleSpan(Typeface.BOLD),
                    0, error.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
            mError.setText(spannable);
            mError.setVisibility(View.VISIBLE);
        } else {
            mError.setText(null);
        }
    }
}