package de.sebse.fuplanner.services.kvv.types;


import android.annotation.SuppressLint;

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

import androidx.annotation.NonNull;

public class GroupedEvents extends EventList {
    private final ArrayList<Group> arrayList = new ArrayList<>();
    private int skippedDayCount = 0;

    public boolean add(Event event) {
        boolean result = super.add(event);
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(event.getStartDate());
        long dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        for (Group group : arrayList) {
            if (group.add(event)) {
                return result;
            }
        }
        arrayList.add(new Group(event));
        return result;
    }

    public List<Group> getGroups() {
        return Collections.unmodifiableList(arrayList);
    }

    public int getSkippedDayCount() {
        return skippedDayCount;
    }

    public class Group {
        private long firstDate;
        private long lastDate;
        private final ArrayList<Long> skippedDates;

        private final int dayOfWeek;
        private final long startTime;
        private final long duration;

        private Group(Event event) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(event.getStartDate());
            dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
            startTime = calendar.get(Calendar.HOUR_OF_DAY)*3600000+calendar.get(Calendar.MINUTE)*60000+calendar.get(Calendar.SECOND)*1000+calendar.get(Calendar.MILLISECOND);
            duration = event.getEndDate()-event.getStartDate();

            skippedDates = new ArrayList<>();
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            firstDate = calendar.getTimeInMillis();
            lastDate = firstDate;
        }

        private boolean add(Event event) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(event.getStartDate());
            int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
            int startTime = calendar.get(Calendar.HOUR_OF_DAY)*3600000+calendar.get(Calendar.MINUTE)*60000+calendar.get(Calendar.SECOND)*1000+calendar.get(Calendar.MILLISECOND);
            long length = event.getEndDate()-event.getStartDate();
            if (this.dayOfWeek != dayOfWeek || this.startTime != startTime || this.duration != length)
                return false;
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            long date = calendar.getTimeInMillis();
            if (date < firstDate) {
                firstDate = addDays(firstDate, -7);
                while (firstDate > date) {
                    skippedDates.add(firstDate);
                    skippedDayCount += 1;
                    firstDate = addDays(firstDate, -7);
                }
            } else if (date > lastDate) {
                lastDate = addDays(lastDate, 7);
                while (lastDate < date) {
                    skippedDates.add(lastDate);
                    skippedDayCount += 1;
                    lastDate = addDays(lastDate, 7);
                }
            } else {
                skippedDates.remove(date);
                skippedDayCount -= 1;
            }
            return true;
        }

        private long addDays(long timeInMillis, int days) {
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(timeInMillis);
            calendar.add(Calendar.DAY_OF_YEAR, days);
            return calendar.getTimeInMillis();
        }

        public long getFirstDate() {
            return firstDate;
        }

        public long getLastDate() {
            return lastDate;
        }

        public List<Long> getSkippedDates() {
            return Collections.unmodifiableList(skippedDates);
        }

        public int getDayOfWeek() {
            return dayOfWeek;
        }

        public long getStartTime() {
            return startTime;
        }

        public long getDuration() {
            return duration;
        }

        @SuppressLint("DefaultLocale")
        @NonNull
        @Override
        public String toString() {
            return String.format("%d - %d - %d - %s", dayOfWeek, startTime, duration, skippedDates);
        }
    }
}
