import {useMutation, useQueryClient} from "react-query";
import firestore from "@react-native-firebase/firestore";
import {useAuthContext} from "@/contexts/AuthContext";
import {DAYS_OF_WEEK_ENUM, IToDo, REPEAT_TYPE} from "@/hooks/firebase/types/todoData";
import {addDays, addMonths, addWeeks, addYears, compareAsc, format, subDays} from "date-fns";

export const daysOfWeek = [
    DAYS_OF_WEEK_ENUM.MONDAY,
    DAYS_OF_WEEK_ENUM.TUESDAY,
    DAYS_OF_WEEK_ENUM.WEDNESDAY,
    DAYS_OF_WEEK_ENUM.THURSDAY,
    DAYS_OF_WEEK_ENUM.FRIDAY,
    DAYS_OF_WEEK_ENUM.SATURDAY,
    DAYS_OF_WEEK_ENUM.SUNDAY];

export const useCreateTodo = () => {
    const { user: currentUser, profileData } = useAuthContext();
    const queryClients = useQueryClient();

    return useMutation({
        mutationKey: ["createTodo"],
        mutationFn: async (todoData: Partial<IToDo>) => {
            try {
                if (todoData.repeatType === REPEAT_TYPE.NONE) {
                    const newDoc = firestore().collection('Todos').doc();
                    let originalTodo = {...todoData, id: newDoc.id, familyId: profileData?.familyId, creatorId: currentUser?.uid}
                    await firestore()
                        .collection("Todos")
                        .add(originalTodo);
                } else {
                    // Create the one original to do
                    const newDoc = firestore().collection('Todos').doc();
                    let originalTodo = {...todoData, id: newDoc.id, familyId: profileData?.familyId, creatorId: currentUser?.uid, connectedTodoId: newDoc.id};

                    originalTodo = resolveTodoAlternatingAssignees(todoData, originalTodo, 0);

                    await firestore()
                        .collection("Todos")
                        .add(originalTodo);

                    const batch = firestore().batch();

                    if (todoData.repeatType === REPEAT_TYPE.DAILY) {
                        // for the next 52 weeks
                        for (let i = 1; i < 52; i++) {
                            let date = originalTodo.date;
                            const nextWeek = addWeeks(date, i);

                            let docRef = firestore().collection("Todos").doc();
                            let newTodo = { ...originalTodo, id: docRef.id, date: nextWeek, connectedTodoId: newDoc.id };
                            newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, i);

                            batch.set(docRef, newTodo);
                        }
                    } else if (todoData.repeatType === REPEAT_TYPE.EVERY_WEEK) {

                        let date = originalTodo.date;
                        let repeatDays = originalTodo.repeatDays;
                        const dates = [];

                        const originalDateDay = format(date, 'EEEE');
                        const originalNumber = daysOfWeek.indexOf(originalDateDay);
                        repeatDays?.forEach((day) => {
                            let number = daysOfWeek.indexOf(day);
                            let newDate;
                            if (originalNumber > number) {
                                let diff = originalNumber - number;
                                newDate = subDays(date, diff);
                            } else {
                                let diff = number - originalNumber;
                                newDate = addDays(date, diff);
                            }
                            dates.push(newDate);
                        });

                        let index = 1;
                        for (let i = 0; i < 52; i++) {
                           dates?.forEach((dateToAdd) => {
                               index ++;
                               let newTodoDate = addWeeks(dateToAdd, i);
                               if (compareAsc(newTodoDate, originalTodo.date) !== 0) {

                                   let docRef = firestore().collection("Todos").doc();
                                   let newTodo = { ...originalTodo, id: docRef.id, date: newTodoDate, connectedTodoId: newDoc.id };
                                   newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, index);

                                   batch.set(docRef, newTodo);
                               }
                           })
                        }
                    } else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_MONTH) {

                        // for the next 12 months
                        for (let i = 1; i < 12; i++) {
                            let date = originalTodo.date;
                            const nextMonth = addMonths(date, i);

                            let docRef = firestore().collection("Todos").doc();
                            let newTodo = { ...originalTodo, id: docRef.id, date: nextMonth, connectedTodoId: newDoc.id };
                            newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, i);

                            batch.set(docRef, newTodo);
                        }
                    } else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_YEAR) {

                        // for the next 5 years
                        for (let i = 1; i < 5; i++) {
                            let date = originalTodo.date;
                            const nextMonth = addYears(date, i);

                            let docRef = firestore().collection("Todos").doc();
                            let newTodo = { ...originalTodo, id: docRef.id, date: nextMonth, connectedTodoId: newDoc.id };
                            newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, i);

                            batch.set(docRef, newTodo);
                        }
                    }

                    await batch.commit();
                }
            } catch (e) {
                console.error(e)
            }
        },
        onSuccess: () => {
            queryClients.invalidateQueries("todos")
        }
    })
}

export const resolveTodoAlternatingAssignees = (todoData, newTodo, i) => {
    if (todoData.assignees && todoData.rotate && todoData?.assignees?.length !== 0) {
        const assignees = todoData.assignees;
        const assignee = assignees[i % assignees.length];

        newTodo = {...newTodo, assignees: [assignee]};
    }

    return newTodo;
}