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

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

    return useMutation({
        mutationKey: ["updateTodo"],
        mutationFn: async (todoData: Partial<IToDo>) => {
            try {
                if (todoData.connectedTodoId) {
                    console.log("CONNECTED")
                    const snapshot = await firestore()
                        .collection("Todos")
                        .where("connectedTodoId", "==", todoData.connectedTodoId)
                        .get();
                    const connectedTodos = snapshot.docs.map((doc) => {
                        const data = doc.data();

                        return {
                            ...data,
                            id: doc.id,
                            date: data.date ? new Date(data.date.seconds * 1000) : null,
                            ref: doc.ref
                        };
                    }) as IToDo[];

                    console.log("CONNECTED TODO");
                    let filteredTodos = connectedTodos?.filter((item) => compareAsc(format(item.date, 'yyyy-MM-dd'), format(todoData.date, 'yyyy-MM-dd')) === 1 ||
                        compareAsc(format(item.date, 'yyyy-MM-dd'), format(todoData.date, 'yyyy-MM-dd')) === 0).sort((a,b) =>{
                        return b.date?.getSeconds() - a.date?.getSeconds();
                    });

                    let firstTodo = filteredTodos?.[0];
                    const batch = firestore().batch();
                    if (compareAsc(format(firstTodo?.date, 'yyyy-MM-dd'), format(todoData.date, 'yyyy-MM-dd')) !== 0 || firstTodo?.repeatType !== todoData.repeatType) {

                        console.log("DELETE");
                        filteredTodos?.forEach((item) => {
                            batch.delete(item.ref);
                        });

                        if (todoData.repeatType === REPEAT_TYPE.NONE) {

                            console.log("NONE");
                            const newDoc = firestore().collection('Todos').doc();
                            let originalTodo = {...todoData, id: newDoc.id, familyId: profileData?.familyId, creatorId: currentUser?.uid}
                            batch.set(newDoc, originalTodo);
                        } else if (todoData.repeatType === REPEAT_TYPE.EVERY_WEEK) {

                            console.log("EVERY WEEK");
                            let date = todoData?.date;
                            let repeatDays = todoData?.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 todosToAddCycles = 4;
                            if (firstTodo?.repeatType === REPEAT_TYPE.EVERY_WEEK) {
                                todosToAddCycles = filteredTodos?.length / firstTodo?.repeatDays?.length;
                            }
                            console.log(todosToAddCycles);
                            let newDoc = firestore().collection("Todos").doc();
                            let originalTodo = { ...todoData, id: newDoc.id, date: todoData.date, connectedTodoId: newDoc?.id };
                            originalTodo = resolveTodoAlternatingAssignees(todoData, originalTodo, 0);
                            batch.set(newDoc, originalTodo);

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

                                        let docRef = firestore().collection("Todos").doc();
                                        let newTodo = { ...todoData, 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) {

                            console.log("ONCE A MONTH");
                            // for the next 12 months
                            for (let i = 0; i < 12; i++) {
                                let date = todoData?.date;
                                const nextMonth = addMonths(date, i);

                                let docRef = firestore().collection("Todos").doc();
                                let newTodo = { ...todoData, id: docRef.id,  date: nextMonth, connectedTodoId: firstTodo?.connectedTodoId };
                                newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, i);
                                batch.set(docRef, newTodo);
                            }
                        } else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_YEAR) {

                            console.log("ONCE A YEAR");
                            // for the next 5 years
                            for (let i = 0; i < 5; i++) {
                                let date = todoData?.date;
                                const nextMonth = addYears(date, i);

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

                        await batch.commit();
                    } else if (firstTodo?.repeatDays !== todoData.repeatDays) {

                        console.log("UPDATE REPEAT DAYS");
                        await updateRepeatDaysTodos(batch, todoData, firstTodo, filteredTodos)
                    } else {
                        filteredTodos?.forEach((item) => {

                            console.log("UPDATE");
                            batch.update(item.ref, {...todoData, date: item.date});
                        })
                        await batch.commit();
                    }
                } else {
                    console.log("REGULAR UPDATE");
                    console.log(todoData);
                    await firestore()
                        .collection("Todos")
                        .doc(todoData.id)
                        .update(todoData);
                }
            } catch (e) {
                console.error(e)
            }
        },
        onSuccess: () => {
            queryClients.invalidateQueries("todos")
        }
    })
}

const updateRepeatDaysTodos = async (batch: any, todoData: IToDo, firstTodo: IToDo, filteredTodos: IToDo[]) => {
    const todosToAddCycles = filteredTodos?.length / firstTodo?.repeatDays?.length;
    console.log(todosToAddCycles);

    filteredTodos?.forEach((item) => {

        batch.update(item.ref, {...todoData, date: item.date});
    })

    let newRepeatDays = todoData.repeatDays?.filter((element) => firstTodo?.repeatDays?.indexOf(element) === -1);
    let removeRepeatDays = firstTodo?.repeatDays?.filter((element) => todoData?.repeatDays?.indexOf(element) === -1);
    const dates = [];

    let date = firstTodo?.date;
    const originalDateDay = format(date, 'EEEE');
    const originalNumber = daysOfWeek.indexOf(originalDateDay);
    newRepeatDays?.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 = 0;
    for (let i = 0; i < todosToAddCycles; i++) {
        dates?.forEach((dateToAdd) => {
            index ++;
            let newTodoDate = addWeeks(dateToAdd, i);
            if (compareAsc(newTodoDate, firstTodo?.date) !== 0) {
                let newTodo = {...todoData, date: newTodoDate};
                newTodo = resolveTodoAlternatingAssignees(todoData, newTodo, index);

                let docRef = firestore().collection("Todos").doc();
                batch.set(docRef, newTodo);
            }
        })
    }

    removeRepeatDays?.forEach((removeDay) => {
        filteredTodos?.forEach((item) => {

            let todoDate = item.date;
            const todoDateDay = format(todoDate, 'EEEE');

            if (todoDateDay === removeDay) {
                batch.delete(item.ref);
            }
        })
    })
    await batch.commit();
}