package de.sebse.fuplanner.fragments;

import android.app.AlertDialog;
import android.content.Context;
import android.graphics.RectF;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;

import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import de.sebse.fuplanner.R;
import de.sebse.fuplanner.services.kvv.types.Event;
import de.sebse.fuplanner.services.kvv.types.Modules;
import de.sebse.fuplanner.tools.UtilsDate;
import de.sebse.fuplanner.tools.MainActivityListener;
import de.sebse.fuplanner.tools.logging.Logger;
import de.sebse.fuplanner.tools.ui.weekview.MonthLoader;
import de.sebse.fuplanner.tools.ui.weekview.WeekView;
import de.sebse.fuplanner.tools.ui.weekview.WeekViewEvent;

/**
 * A simple {@link Fragment} subclass.
 * Activities that contain this fragment must implement the
 * {@link MainActivityListener} interface
 * to handle interaction events.
 * Use the {@link ScheduleFragment#newInstance} factory method to
 * create an instance of this fragment.
 *
 */
public class ScheduleFragment extends Fragment implements
        MonthLoader.MonthChangeListener,
        WeekView.ScrollListener,
        WeekView.DoubleTapLeftRightListener,
        WeekView.EventClickListener {
    private MainActivityListener mListener;
    private WeekView mWeekView;
    private final Logger log = new Logger(this);
    private Modules mModules = null;

    public ScheduleFragment() {
        // Required empty public constructor
    }

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @return A new instance of fragment ScheduleFragment.
     */
    public static ScheduleFragment newInstance() {
        ScheduleFragment fragment = new ScheduleFragment();
        Bundle args = new Bundle();
        fragment.setArguments(args);
        return fragment;
    }

    public void invalidate(boolean forceRefresh) {
        if (mListener == null) return;
        mListener.getKVV().modules().list().recv(modules -> {
            mModules = modules;
            final int[] i = {0};
            for (Modules.Module module: mModules) {
                mListener.getKVV().modules().events().recv(module, success1 -> {
                    i[0]++;
                    if (i[0] >= mModules.size()) {
                        if (mWeekView != null) {
                            mWeekView.invalidate();
                            mWeekView.notifyDatasetChanged();
                        }
                    }
                }, log::e, forceRefresh);
            }
        }, log::e, forceRefresh);
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View v = inflater.inflate(R.layout.fragment_schedule, container, false);
        mWeekView = v.findViewById(R.id.weekView);
        mWeekView.setMonthChangeListener(this);
        mWeekView.setScrollListener(this);
        mWeekView.setDoubleTapLeftRightListener(this);
        mWeekView.setOnEventClickListener(this);
        invalidate(false);
        return v;
    }





    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof MainActivityListener) {
            mListener = (MainActivityListener) context;
        } else {
            throw new RuntimeException(context.toString()
                    + " must implement OnFragmentInteractionListener");
        }
        mListener.onTitleTextChange(R.string.schedule);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mListener = null;
    }

    @Override
    public List<? extends WeekViewEvent> onMonthChange(int newYear, int newMonth) {
        ArrayList<WeekViewEvent> events = new ArrayList<>();
        if (mModules != null){
            for (Modules.Module mod: mModules) {
                if (mod.events != null) {
                    Iterator<Event> it_modEvents = mod.events.getEventsOfMonth(newYear, newMonth);
                    while (it_modEvents.hasNext()) {
                        Event e = it_modEvents.next();

                        Calendar end = Calendar.getInstance();
                        end.setTimeInMillis(e.getEndDate());
                        Calendar start = Calendar.getInstance();
                        start.setTimeInMillis(e.getStartDate());

                        WeekViewEvent weekViewEvent = new WeekViewEvent(e.getModuleId()+"/"+e.getId(), e.getTitle(), e.getLocation(), start, end);
                        weekViewEvent.setColor(e.getColor());
                        events.add(weekViewEvent);
                    }
                }
            }

        }
        return events;
    }

    @Override
    public void onFirstVisibleDayChanged(Calendar newFirstVisibleDay, Calendar oldFirstVisibleDay) {
        Calendar newLastVisibleDay = (Calendar) newFirstVisibleDay.clone();
        newLastVisibleDay.add(Calendar.HOUR, 24*mWeekView.getNumberOfVisibleDays());
        mListener.onTitleTextChange(getResources().getString(R.string.date_scale, UtilsDate.getModifiedDate(newFirstVisibleDay.getTimeInMillis()), UtilsDate.getModifiedDate(newLastVisibleDay.getTimeInMillis())));
    }


    public void goToToday() {
        mWeekView.goToToday();
    }

    @Override
    public void onDoubleTapLeftRightListener(boolean isRight) {
        Calendar firstVisibleDay = mWeekView.getFirstVisibleDay();
        // skip to next week
        if (isRight){
            firstVisibleDay.add(Calendar.DATE, 1);
            while (firstVisibleDay.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
                firstVisibleDay.add(Calendar.DATE, 1);
            }
        }
        else {
            firstVisibleDay.add(Calendar.DATE, -1);
            while (firstVisibleDay.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
                firstVisibleDay.add(Calendar.DATE, -1);
            }
        }
        mWeekView.goToDate(firstVisibleDay);
        onFirstVisibleDayChanged(firstVisibleDay, mWeekView.getLastVisibleDay());
    }

    @Override
    public void onEventClick(WeekViewEvent event, RectF eventRect) {
        String[] idParts = event.getIdentifier().split("/");
        String moduleId = idParts[0];
        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getContext());

        if (mListener == null) return;
        mListener.getKVV().modules().list().find(moduleId, module -> {
            String moduleName = module.title;
            alertDialogBuilder
                    .setTitle(event.getName())
                    .setMessage(
                            getResources().getString(R.string.module_name, moduleName) + "\n" +
                                    getResources().getString(R.string.location_name, event.getLocation()) + "\n" +
                                    getResources().getString(R.string.date_scale, UtilsDate.getModifiedTime(getContext(), event.getStartTime().getTimeInMillis()), UtilsDate.getModifiedTime(getContext(), event.getEndTime().getTimeInMillis()+1))
                    )
                    .setCancelable(true)
                    .setNeutralButton(R.string.close, (dialog, id) -> dialog.cancel());

            AlertDialog alertDialog = alertDialogBuilder.create();
            alertDialog.show();
        }, log::e);
    }
}
