package de.sebse.fuplanner.fragments.moddetails;

import android.content.Context;
import android.content.res.Resources;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import de.sebse.fuplanner.R;
import de.sebse.fuplanner.services.kvv.types.Event;
import de.sebse.fuplanner.services.kvv.types.EventList;
import de.sebse.fuplanner.services.kvv.types.GroupedEvents;
import de.sebse.fuplanner.services.kvv.types.Modules;
import de.sebse.fuplanner.tools.UtilsDate;
import de.sebse.fuplanner.tools.logging.Logger;
import de.sebse.fuplanner.tools.ui.CustomViewHolder;
import de.sebse.fuplanner.tools.ui.ItemViewHolder;
import de.sebse.fuplanner.tools.ui.StringViewHolder;

class ModDetailEventAdapter extends RecyclerView.Adapter<CustomViewHolder> {
    private static final String VALUE_LECTURE = "Class section - Lecture";
    private static final String VALUE_TUTORIAL = "Class section - Small Group";
    private static final String VALUE_EXAM = "Exam";
    private static final String VALUE_DEADLINE = "Deadline";
    private static final String VALUE_OTHER = "Other";
    private static final String[] VALUES_GROUPED = {VALUE_LECTURE, VALUE_TUTORIAL};
    private static final String[] VALUES_UNGROUPED = {VALUE_EXAM, VALUE_DEADLINE};

    private static final int TYPE_NONE = 0;
    private static final int TYPE_GROUPED = 1;
    private static final int TYPE_UNGROUPED = 2;
    private static final int TYPE_HEADER = 3;

    private Modules.Module mValue;
    private final ArrayList<Pair<Integer, Object>> mPositionalData;

    private final Logger log = new Logger(this);

    ModDetailEventAdapter() {
        mValue = null;
        mPositionalData = new ArrayList<>();
        //mListener = listener;
    }

    public void setModule(Modules.Module module) {
        mValue = module;
        this.setModule();
    }

    private void setModule() {
        LinkedHashMap<String, GroupedEvents> listsGrouped = new LinkedHashMap<>();
        LinkedHashMap<String, EventList> listsUngrouped = new LinkedHashMap<>();
        for (String value : VALUES_GROUPED) listsGrouped.put(value, new GroupedEvents());
        for (String value : VALUES_UNGROUPED) listsUngrouped.put(value, new EventList());
        listsUngrouped.put(VALUE_OTHER, new EventList());
        for (int i = 0; i < getEventsCount(); i++) {
            assert mValue.events != null;
            Event event = mValue.events.get(i);
            String type = event.getType();
            GroupedEvents groupedEvents = listsGrouped.get(type);
            if (groupedEvents != null) {
                groupedEvents.add(event);
            } else {
                EventList ungroupedEvents = listsUngrouped.get(type);
                if (ungroupedEvents == null) {
                    ungroupedEvents = listsUngrouped.get(VALUE_OTHER);
                }
                assert ungroupedEvents != null;
                ungroupedEvents.add(event);
            }
        }

        mPositionalData.clear();
        for (Map.Entry<String, GroupedEvents> value: listsGrouped.entrySet()) {
            if (value.getValue().getGroups().size() > 0) {
                mPositionalData.add(new Pair<>(TYPE_HEADER, value.getKey()));
                boolean showAsGrouped = true;
                for (GroupedEvents.Group group : value.getValue().getGroups()) {
                    if (group.getSkippedDates().size() > 2) {
                        showAsGrouped = false;
                        break;
                    }
                }
                if (showAsGrouped) {
                    for (GroupedEvents.Group group : value.getValue().getGroups()) {
                        mPositionalData.add(new Pair<>(TYPE_GROUPED, group));
                    }
                } else {
                    for (Event event : value.getValue()) {
                        mPositionalData.add(new Pair<>(TYPE_UNGROUPED, event));
                    }
                }
            }
        }
        for (Map.Entry<String, EventList> value: listsUngrouped.entrySet()) {
            if (value.getValue().size() > 0) {
                mPositionalData.add(new Pair<>(TYPE_HEADER, value.getKey()));
                for (Event event : value.getValue()) {
                    mPositionalData.add(new Pair<>(TYPE_UNGROUPED, event));
                }
            }
        }
        if (mPositionalData.size() == 0)
            mPositionalData.add(new Pair<>(TYPE_NONE, null));
        this.notifyDataSetChanged();
    }

    @NonNull
    @Override
    public CustomViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view;
        switch (viewType) {
            case TYPE_GROUPED:
            case TYPE_UNGROUPED:
                view = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.list_all_items, parent, false);
                return new ItemViewHolder(view);
            case TYPE_HEADER:
                view = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.list_all_caption, parent, false);
                return new StringViewHolder(view);
            default:
                view = LayoutInflater.from(parent.getContext())
                        .inflate(R.layout.list_all_no_items, parent, false);
                return new CustomViewHolder(view);
        }
    }

    @Override
    public int getItemViewType(int position) {
        // Note that unlike in ListView adapters, types don't have to be contiguous
        return mPositionalData.get(position).first;
    }

    @Override
    public void onBindViewHolder(@NonNull final CustomViewHolder holder, int position) {
        if (mValue == null || position > mPositionalData.size())
            return;
        Pair<Integer, Object> data = mPositionalData.get(position);
        Resources resources = holder.mView.getResources();
        Context context = holder.mView.getContext();
        switch (data.first) {
            case TYPE_HEADER:
                StringViewHolder s = (StringViewHolder) holder;
                String title = "";
                if (VALUE_LECTURE.equals(data.second)) {
                    title = resources.getString(R.string.lecture);

                } else if (VALUE_TUTORIAL.equals(data.second)) {
                    title = resources.getString(R.string.tutorial);

                } else if (VALUE_EXAM.equals(data.second)) {
                    title = resources.getString(R.string.exam);

                } else if (VALUE_DEADLINE.equals(data.second)) {
                    title = resources.getString(R.string.deadline);

                } else if (VALUE_OTHER.equals(data.second)) {
                    title = resources.getString(R.string.others);
                }
                s.mString.setText(title);
                return;
            case TYPE_GROUPED:
                ItemViewHolder ig = (ItemViewHolder) holder;
                GroupedEvents.Group group = ((GroupedEvents.Group) data.second);
                long firstDateTime = group.getFirstDate()+group.getStartTime();
                long lastDateTime = group.getLastDate()+group.getStartTime()+group.getDuration();
                String start, end, weekday, startTime, endTime;
                StringBuilder excepts = null;
                start = UtilsDate.getModifiedDate(firstDateTime);
                end = UtilsDate.getModifiedDate(lastDateTime);
                weekday = UtilsDate.getModifiedDate(context, firstDateTime, "E");
                startTime = UtilsDate.getModifiedTime(context, firstDateTime);
                endTime = UtilsDate.getModifiedTime(context, lastDateTime);
                for (long skippedDate : group.getSkippedDates()) {
                    if (excepts == null) {
                        excepts = new StringBuilder(UtilsDate.getModifiedDate(skippedDate));
                    } else {
                        excepts.append(", ").append(UtilsDate.getModifiedDate(skippedDate));
                    }
                }
                ig.mTitle.setText(context.getString(R.string.event_scale, weekday, startTime, endTime));
                ig.mSubLeft.setText(context.getString(R.string.date_scale, start, end));
                ig.mSubRight.setText(excepts != null ? context.getString(R.string.except_list, excepts.toString()) : "");
                return;
            case TYPE_UNGROUPED:
                ItemViewHolder iu = (ItemViewHolder) holder;
                Event event = (Event) data.second;
                String date;
                if (UtilsDate.dateEquals(event.getStartDate(), System.currentTimeMillis()))
                    start = UtilsDate.getModifiedTime(context, event.getStartDate());
                else
                    start = UtilsDate.getModifiedDateTime(context, event.getStartDate());
                if (UtilsDate.dateEquals(event.getStartDate(), event.getEndDate()))
                    end = UtilsDate.getModifiedTime(context, event.getEndDate());
                else
                    end = UtilsDate.getModifiedDateTime(context, event.getEndDate());
                date = context.getString(R.string.date_scale, start, end);
                iu.mTitle.setText(event.getTitle());
                iu.mSubLeft.setText(date);
                iu.mSubRight.setText("");
        }
    }

    @Override
    public int getItemCount() {
        return mPositionalData.size();
    }

    private int getEventsCount() {
        if (mValue.events != null)
            return mValue.events.size();
        return 0;
    }
}
