package com.jachdev.consumerprotection.ui.home;

import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;

import com.airbnb.lottie.LottieAnimationView;
import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.components.Description;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.components.XAxis;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.formatter.IndexAxisValueFormatter;
import com.jachdev.commonlibs.base.BaseFragment;
import com.jachdev.commonlibs.widget.CustomTextView;
import com.jachdev.consumerprotection.R;
import com.jachdev.consumerprotection.data.LipidProfile;
import com.jachdev.consumerprotection.data.User;
import com.jachdev.consumerprotection.data.enums.TestReportType;
import com.jachdev.consumerprotection.ui.exercise.ExercisePlanActivity;
import com.jachdev.consumerprotection.ui.MealPlanActivity;
import com.jachdev.consumerprotection.ui.bot.BotActivity;

import org.jetbrains.annotations.NotNull;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.LinearLayoutCompat;
import androidx.core.app.ActivityCompat;
import androidx.core.widget.NestedScrollView;
import androidx.lifecycle.Observer;
import androidx.lifecycle.ViewModelProvider;
import butterknife.BindView;
import butterknife.OnClick;

public class HomeFragment extends BaseFragment {

    @BindView(R.id.tv_header)
    CustomTextView tvHeader;

    private HomeViewModel homeViewModel;
    private FragmentEventListener listener;

    private TestReportType testReportType;
    private List<LipidProfile> lipidProfiles;

    private boolean isHelpNeeded = false;

    @BindView(R.id.chart)
    BarChart chart;
    @BindView(R.id.lav)
    LottieAnimationView lav;
    @BindView(R.id.scrollView)
    NestedScrollView scrollView;
    @BindView(R.id.layout_suggestions)
    LinearLayoutCompat layoutSuggestions;
    @BindView(R.id.layout_animation)
    LinearLayoutCompat layoutAnimation;
    @BindView(R.id.tvXAxisLabel)
    CustomTextView tvXAxisLabel;
    @BindView(R.id.tvYAxisLabel)
    CustomTextView tvYAxisLabel;
    @BindView(R.id.tv_tips)
    CustomTextView tvTips;

    @Override
    protected int layoutRes() {
        return R.layout.fragment_home;
    }

    @Override
    public void onViewCreated(@NonNull @NotNull View view, @Nullable @org.jetbrains.annotations.Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        homeViewModel =
                new ViewModelProvider(this).get(HomeViewModel.class);

        init();

        homeViewModel.getUser().observe(getViewLifecycleOwner(), mUserObserver);
        homeViewModel.getLipidProfileData().observe(getViewLifecycleOwner(), mLipidProfileObserver);
    }

    @Override
    public void onResume() {
        super.onResume();
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        listener = (FragmentEventListener) context;
    }

    @OnClick(R.id.tv_glu)
    public void onGluClick(){
        testReportType = TestReportType.GLUCOSE;
        isHelpNeeded = false;

        setXYAxis();
        drawDiagram();
    }

    @OnClick(R.id.tv_chol)
    public void onCholClick(){
        testReportType = TestReportType.CHOLESTEROL;
        isHelpNeeded = false;

        setXYAxis();
        drawDiagram();
    }

    @OnClick(R.id.tv_hdl)
    public void onHdlClick(){
        testReportType = TestReportType.HDL;
        isHelpNeeded = false;

        setXYAxis();
        drawDiagram();
    }

    @OnClick(R.id.tv_ldl)
    public void onLdlClick(){
        testReportType = TestReportType.LDL;
        isHelpNeeded = false;

        setXYAxis();
        drawDiagram();
    }

    @OnClick(R.id.btn_talk_to_us)
    public void onTalkToUsClick(){

        getBaseActivity().startActivity(new Intent(getBaseActivity(), BotActivity.class));
    }

    @OnClick(R.id.btn_meal_plan)
    public void onMealPlanClick(){

        getBaseActivity().startActivity(new Intent(getBaseActivity(), MealPlanActivity.class));
    }

    @OnClick(R.id.btn_exercise_plan)
    public void onExercisePlanClick(){

        getBaseActivity().startActivity(new Intent(getBaseActivity(), ExercisePlanActivity.class));
    }

    @OnClick(R.id.tv_tips)
    public void onTipsClick(){
        scrollView.smoothScrollTo(1000, 1000, 500);
    }

    private void init() {
        testReportType = TestReportType.GLUCOSE;

//        chart.zoom(28f,1f,0f,0f);
        chart.setPinchZoom(false);
        chart.setDoubleTapToZoomEnabled(false);
        Description d = new Description();
        d.setText("");
        chart.setDescription(d);

        setXYAxis();

        homeViewModel.getUserData();
        homeViewModel.getLipidProfile();
    }

    private void setXYAxis() {
        tvXAxisLabel.setAnyText("Time");

        String yLabel = testReportType.getName() + " (mg/dl)";
        tvYAxisLabel.setAnyText(yLabel);

        //hiding the grey background of the chart, default false if not set
        chart.setDrawGridBackground(false);
        //remove the bar shadow, default false if not set
        chart.setDrawBarShadow(false);
        //remove border of the chart, default false if not set
        chart.setDrawBorders(false);

        //remove the description label text located at the lower right corner
        Description description = new Description();
        description.setEnabled(false);
        chart.setDescription(description);

        //setting animation for y-axis, the bar will pop up from 0 to its value within the time we set
        chart.animateY(500);
        //setting animation for x-axis, the bar will pop up separately within the time we set
        chart.animateX(500);

        XAxis xAxis = chart.getXAxis();
        //change the position of x-axis to the bottom
        xAxis.setPosition(XAxis.XAxisPosition.BOTTOM);
        //set the horizontal distance of the grid line
        xAxis.setGranularity(1f);
        //hiding the x-axis line, default true if not set
        xAxis.setDrawAxisLine(false);
        //hiding the vertical grid lines, default true if not set
        xAxis.setDrawGridLines(false);

        YAxis leftAxis = chart.getAxisLeft();
        //hiding the left y-axis line, default true if not set
        leftAxis.setDrawAxisLine(true);

        YAxis rightAxis = chart.getAxisRight();
        //hiding the right y-axis line, default true if not set
        rightAxis.setDrawAxisLine(false);

        Legend legend = chart.getLegend();
        //setting the shape of the legend form to line, default square shape
        legend.setForm(Legend.LegendForm.LINE);
        //setting the text size of the legend
        legend.setTextSize(8f);
        //setting the alignment of legend toward the chart
        legend.setVerticalAlignment(Legend.LegendVerticalAlignment.BOTTOM);
        legend.setHorizontalAlignment(Legend.LegendHorizontalAlignment.LEFT);
        //setting the stacking direction of legend
        legend.setOrientation(Legend.LegendOrientation.HORIZONTAL);
        //setting the location of legend outside the chart, default false if not set
        legend.setDrawInside(false);
    }

    private Observer<? super User> mUserObserver = new Observer<User>() {
        @Override
        public void onChanged(@Nullable User user) {
            String header = getString(R.string.hello) + " " + user.getName();
            tvHeader.setAnyText(header);
        }
    };

    private Observer<? super List<LipidProfile>> mLipidProfileObserver = new Observer<List<LipidProfile>>() {
        @Override
        public void onChanged(List<LipidProfile> lipidProfiles) {
            HomeFragment.this.lipidProfiles = lipidProfiles;

            drawDiagram();
        }
    };

    private void drawDiagram() {
        List<BarEntry> entries = new ArrayList<BarEntry>();
        List<Integer> colors = new ArrayList<Integer>();
        int max = 0;
        int min = 1000000;

        if(lipidProfiles == null)
            return;

        for (int x = 0; x < lipidProfiles.size(); x++) {
            LipidProfile d = lipidProfiles.get(x);
            long date = d.getCreatedAt();
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(date*1000);
            int value = 0;

            switch (testReportType){
                case GLUCOSE:
                    value = (int) Double.parseDouble(d.getGlu());
                    break;
                case CHOLESTEROL:
                    value = (int) Double.parseDouble(d.getCho());
                    break;
                case HDL:
                    value = (int) Double.parseDouble(d.getHdl());
                    break;
                case LDL:
                    value = (int) Double.parseDouble(d.getLdl());
                    break;
            }

            if(max < value)
                max = value;

            if(min > value)
                min = value;

            if(value >= testReportType.getMax() || value <= testReportType.getMin()){
                colors.add(ActivityCompat.getColor(getActivity(), R.color.color_danger));
                isHelpNeeded = true;
            }else if(isMiddleOf(value, testReportType.getMax()) || isMiddleOf(value, testReportType.getMin())){
                colors.add(ActivityCompat.getColor(getActivity(), R.color.color_middle));
                isHelpNeeded = true;
            }else{
                colors.add(ActivityCompat.getColor(getActivity(), R.color.color_normal));
            }

            if(date > 0 && value > 0){

                BarEntry entry = new BarEntry(calendar.get(Calendar.MONTH), value);
                entries.add(entry);
            }
        }

        BarDataSet barDataSet = new BarDataSet(entries, testReportType.getName());

        barDataSet.setColors(colors);
        //Setting the size of the form in the legend
        barDataSet.setFormSize(5f);
        //showing the value of the bar, default true if not set
        barDataSet.setDrawValues(true);
        //setting the text size of the value of the bar
        barDataSet.setValueTextSize(12f);

        BarData data = new BarData(barDataSet);
        chart.setData(data);

        YAxis yAxis = chart.getAxisLeft();
        yAxis.setAxisMinimum(0);
        yAxis.setAxisMaximum(max+10f);

        XAxis xAxis = chart.getXAxis();
        xAxis.setValueFormatter(new StickyDateAxisValueFormatter());

        chart.invalidate();

        checkHelpNeeded();
    }

    private void checkHelpNeeded() {
        if (isHelpNeeded){
            lav.setAnimation("nurse.json");
            tvTips.setText(getString(R.string.seems_like_you_need_some_medical_help_from_us));
            layoutSuggestions.setVisibility(View.VISIBLE);
        }else{
            lav.setAnimation("healthy.json");
            tvTips.setText(getString(R.string.you_are_doing_well_keep_it_up));
            layoutSuggestions.setVisibility(View.GONE);
        }

        lav.playAnimation();
        layoutAnimation.setVisibility(View.VISIBLE);
    }

    private boolean isMiddleOf(int value, int level) {
        int min = level - 5;
        int max = level + 5;

        return value > min && value < max;
    }

    public class StickyDateAxisValueFormatter extends IndexAxisValueFormatter {

        @Override
        public String getFormattedValue(float value) {

            // Convert float value to date string
            // Convert from days back to milliseconds to format time  to show to the user
            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.MONTH, (int) value);
            long emissionsMilliSince1970Time = (long) value*1000;
            // Show time in local version
            Date timeMilliseconds = calendar.getTime();
            SimpleDateFormat dateTimeFormat = new SimpleDateFormat("MMM");

            return dateTimeFormat.format(timeMilliseconds);
        }
    }

    public interface FragmentEventListener{
    }
}