package nodomain.freeyourgadget.gadgetbridge.activities.charts;

import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.charts.Chart;
import com.github.mikephil.charting.components.LimitLine;
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.ValueFormatter;

import org.apache.commons.lang3.time.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;

public class StepsPeriodFragment extends StepsFragment<StepsPeriodFragment.StepsData> {
    protected static final Logger LOG = LoggerFactory.getLogger(BodyEnergyFragment.class);

    private TextView mDateView;
    private TextView stepsAvg;
    private TextView stepsTotal;
    private TextView distanceAvg;
    private TextView distanceTotal;
    private BarChart stepsChart;

    protected int CHART_TEXT_COLOR;
    protected int TEXT_COLOR;
    protected int STEPS_GOAL;

    protected int BACKGROUND_COLOR;
    protected int DESCRIPTION_COLOR;

    public static StepsPeriodFragment newInstance ( int totalDays ) {
        StepsPeriodFragment fragmentFirst = new StepsPeriodFragment();
        Bundle args = new Bundle();
        args.putInt("totalDays", totalDays);
        fragmentFirst.setArguments(args);
        return fragmentFirst;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        TOTAL_DAYS = getArguments() != null ? getArguments().getInt("totalDays") : 0;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_steps_period, container, false);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            rootView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
                getChartsHost().enableSwipeRefresh(scrollY == 0);
            });
        }

        mDateView = rootView.findViewById(R.id.steps_date_view);
        stepsChart = rootView.findViewById(R.id.steps_chart);
        stepsAvg = rootView.findViewById(R.id.steps_avg);
        distanceAvg = rootView.findViewById(R.id.distance_avg);
        stepsTotal = rootView.findViewById(R.id.steps_total);
        distanceTotal = rootView.findViewById(R.id.distance_total);
        STEPS_GOAL = GBApplication.getPrefs().getInt(ActivityUser.PREF_USER_STEPS_GOAL, ActivityUser.defaultUserStepsGoal);
        setupStepsChart();
        refresh();

        return rootView;
    }

    protected void setupStepsChart() {
        stepsChart.getDescription().setEnabled(false);
        if (TOTAL_DAYS <= 7) {
            stepsChart.setTouchEnabled(false);
            stepsChart.setPinchZoom(false);
        }
        stepsChart.setDoubleTapToZoomEnabled(false);
        stepsChart.getLegend().setEnabled(false);

        final XAxis xAxisBottom = stepsChart.getXAxis();
        xAxisBottom.setPosition(XAxis.XAxisPosition.BOTTOM);
        xAxisBottom.setDrawLabels(true);
        xAxisBottom.setDrawGridLines(false);
        xAxisBottom.setEnabled(true);
        xAxisBottom.setDrawLimitLinesBehindData(true);
        xAxisBottom.setTextColor(CHART_TEXT_COLOR);

        final YAxis yAxisLeft = stepsChart.getAxisLeft();
        yAxisLeft.setDrawGridLines(true);
        yAxisLeft.setDrawTopYLabelEntry(true);
        yAxisLeft.setEnabled(true);
        yAxisLeft.setTextColor(CHART_TEXT_COLOR);
        yAxisLeft.setAxisMinimum(0f);
        final LimitLine goalLine = new LimitLine(STEPS_GOAL);
        goalLine.setLineColor(getResources().getColor(R.color.steps_color));
        goalLine.setLineWidth(1.5f);
        goalLine.enableDashedLine(15f, 10f, 0f);
        yAxisLeft.addLimitLine(goalLine);

        final YAxis yAxisRight = stepsChart.getAxisRight();
        yAxisRight.setEnabled(true);
        yAxisRight.setDrawLabels(false);
        yAxisRight.setDrawGridLines(false);
        yAxisRight.setDrawAxisLine(true);
    }

        @Override
    public String getTitle() {
        return getString(R.string.steps);
    }

    @Override
    protected void init() {
        TEXT_COLOR = GBApplication.getTextColor(requireContext());
        CHART_TEXT_COLOR = GBApplication.getSecondaryTextColor(requireContext());
        BACKGROUND_COLOR = GBApplication.getBackgroundColor(getContext());
        DESCRIPTION_COLOR = GBApplication.getTextColor(getContext());
        CHART_TEXT_COLOR = GBApplication.getSecondaryTextColor(getContext());
    }

    @Override
    protected StepsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) {
        Calendar day = Calendar.getInstance();
        Date to = new Date((long) this.getTSEnd() * 1000);
        Date from = DateUtils.addDays(to,-(TOTAL_DAYS - 1));
        String toFormattedDate = new SimpleDateFormat("E, MMM dd").format(to);
        String fromFormattedDate = new SimpleDateFormat("E, MMM dd").format(from);
        mDateView.setText(fromFormattedDate + " - " + toFormattedDate);
        day.setTime(to);
        List<StepsDay> stepsDaysData = getMyStepsDaysData(db, day, device);
        return new StepsData(stepsDaysData);
    }

    @Override
    protected void updateChartsnUIThread(StepsData stepsData) {
        stepsChart.setData(null);

        List<BarEntry> entries = new ArrayList<>();
        int counter = 0;
        for(StepsDay day : stepsData.days) {
            entries.add(new BarEntry(counter, day.steps));
            counter++;
        }
        BarDataSet set = new BarDataSet(entries, "Steps");
        set.setDrawValues(true);
        set.setColors(getResources().getColor(R.color.steps_color));
        final XAxis x = stepsChart.getXAxis();
        x.setValueFormatter(getStepsChartDayValueFormatter(stepsData));
        stepsChart.getAxisLeft().setAxisMaximum(Math.max(set.getYMax(), STEPS_GOAL) + 2000);

        BarData barData = new BarData(set);
        barData.setValueTextColor(Color.GRAY); //prevent tearing other graph elements with the black text. Another approach would be to hide the values cmpletely with data.setDrawValues(false);
        barData.setValueTextSize(10f);
        if (TOTAL_DAYS > 7) {
            stepsChart.setRenderer(new AngledLabelsChartRenderer(stepsChart, stepsChart.getAnimator(), stepsChart.getViewPortHandler()));
        }
        stepsChart.setData(barData);
        stepsAvg.setText(String.format(String.valueOf(stepsData.stepsDailyAvg)));
        distanceAvg.setText(getString(R.string.steps_distance_unit, stepsData.distanceDailyAvg));
        stepsTotal.setText(String.format(String.valueOf(stepsData.totalSteps)));
        distanceTotal.setText(getString(R.string.steps_distance_unit, stepsData.totalDistance));
    }

    ValueFormatter getStepsChartDayValueFormatter(StepsPeriodFragment.StepsData stepsData) {
        return new ValueFormatter() {
            @Override
            public String getFormattedValue(float value) {
                StepsPeriodFragment.StepsDay day = stepsData.days.get((int) value);
                String pattern = TOTAL_DAYS > 7 ? "dd" : "EEE";
                SimpleDateFormat formatLetterDay = new SimpleDateFormat(pattern, Locale.getDefault());
                return formatLetterDay.format(new Date(day.day.getTimeInMillis()));
            }
        };
    }

    @Override
    protected void renderCharts() {
        stepsChart.invalidate();
    }

    protected void setupLegend(Chart<?> chart) {}

    protected static class StepsData extends ChartsData {
        List<StepsDay> days;
        long stepsDailyAvg = 0;
        double distanceDailyAvg = 0;
        long totalSteps = 0;
        double totalDistance = 0;
        StepsDay todayStepsDay;
        protected StepsData(List<StepsDay> days) {
            this.days = days;
            int daysCounter = 0;
            for(StepsDay day : days) {
                this.totalSteps += day.steps;
                this.totalDistance += day.distance;
                if (day.steps > 0) {
                    daysCounter++;
                }
            }
            if (daysCounter > 0) {
                this.stepsDailyAvg = this.totalSteps / daysCounter;
                this.distanceDailyAvg = this.totalDistance / daysCounter;
            }
            this.todayStepsDay = days.get(days.size() - 1);
        }
    }
}
