import { useMutation, useQueryClient } from "@tanstack/react-query";
import firestore from "@react-native-firebase/firestore";
import { IToDo, REPEAT_TYPE } from "@/hooks/firebase/types/todoData";
import { compareAsc, format } from "date-fns";
import {
    getNextDailyDates,
    getNextMonthlyDates,
    getNextWeeklyDates,
    getNextYearlyDates
} from "@/hooks/firebase/useCreateTodo";
import { useAuthContext } from "@/contexts/AuthContext";
import {UserProfile} from "@/hooks/firebase/types/profileTypes";

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

    return useMutation({
        mutationKey: ["updateTodo"],
        mutationFn: async (todoData: Partial<IToDo>) => {
            try {
                if (todoData.connectedTodoId) {

                    let nextDates;
                    if (todoData.repeatType === REPEAT_TYPE.DAILY) {
                        nextDates = getNextDailyDates(todoData.date, true);
                    } else if (todoData.repeatType === REPEAT_TYPE.EVERY_WEEK) {
                        nextDates = getNextWeeklyDates(todoData.repeatDays, todoData.date);
                    } else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_MONTH) {
                        nextDates = getNextMonthlyDates(todoData.date, true);
                    } else if (todoData.repeatType === REPEAT_TYPE.ONCE_A_YEAR) {
                        nextDates = getNextYearlyDates(todoData.date, true);
                    }

                    const todosRef = firestore().collection("Todos");
                    const batch = firestore().batch();

                    const snapshot = await todosRef
                        .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 unknown as IToDo[];

                    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();
                    });

                    // Update existing todos or create new ones
                    filteredTodos?.map((todo, index) => {
                        const newDate = nextDates[index];
                        let assignee;
                        if (todoData.assignees && todoData.rotate && todoData?.assignees?.length !== 0) {
                            assignee = todoData.assignees[(index + 1) % todoData.assignees.length];
                        }

                        if (newDate) {
                            const nextTodo = {
                                ...todoData,
                                date: newDate,
                                assignees: todoData.assignees,
                                currentAssignee: assignee
                            }
                            let docRef = todo.ref;
                            batch.update(docRef, nextTodo)
                        } else {
                            return null;
                        }
                    });

                    const existingDates = filteredTodos?.map((todo) => todo.date);
                    nextDates
                        .filter((date) => !existingDates.includes(date))
                        .map((date, index) => {
                            const newDocRef = todosRef.doc();

                            let assignee;
                            if (todoData.assignees && todoData.rotate && todoData?.assignees?.length !== 0) {
                                assignee = todoData.assignees[(index + 1) % todoData.assignees.length];
                            }

                            const nextTodo = {
                                ...todoData,
                                date: date,
                                id: newDocRef.id,
                                familyId: profileData?.familyId,
                                creatorId: currentUser?.uid,
                                connectedTodoId: todoData.connectedTodoId,
                                assignees: todoData.assignees,
                                currentAssignee: assignee
                            }

                            batch.set(newDocRef, nextTodo)
                        });

                    // Remove unmatched todos
                    const unmatchedTodos = filteredTodos?.filter(
                        (item) => !nextDates.includes(item.date)
                    );
                   unmatchedTodos.map((item) =>
                        batch.delete(item.ref)
                    );

                    await batch.commit();
                } else {

                    let documentSnapshot = await firestore().collection("Todos").doc(todoData.id).get();
                    if (documentSnapshot.exists) {
                        let todoUpdate = documentSnapshot.data() as IToDo;

                        const userBatch = firestore().batch();
                        if (todoUpdate.done !== todoData.done) {

                            todoUpdate.assignees?.map(async (userId) => {
                                const userRef = firestore().collection("Profiles").doc(userId);
                                let userSnapshot = await userRef.get();
                                let userData = userSnapshot.data() as UserProfile;

                                if (!userData) return;

                                // Calculate new points
                                let userWeeklyPoints = userData.weeklyPoints ?? 0;
                                const weeklyPoints = todoData.done
                                    ? userWeeklyPoints + todoUpdate.points
                                    : userWeeklyPoints - todoUpdate.points;

                                let pointsPerDay = userData.weeklyDayPoints || {
                                    Monday: 0,
                                    Tuesday: 0,
                                    Wednesday: 0,
                                    Thursday: 0,
                                    Friday: 0,
                                    Saturday: 0,
                                    Sunday: 0,
                                };

                                const currentDay = getCurrentDay();
                                const updatedPointsPerDay = todoData.done
                                    ? pointsPerDay[currentDay] + todoUpdate.points
                                    : pointsPerDay[currentDay] - todoUpdate.points;
                                pointsPerDay[currentDay] = Math.max(0, updatedPointsPerDay);

                                let userAllTimePoints = userData.allTimePoints ?? 0;
                                const allTimePoints = todoData.done
                                    ? userAllTimePoints + todoUpdate.points
                                    : userAllTimePoints - todoUpdate.points;

                                const weeklyCompletedTodos = todoData.done
                                    ? (userData.weeklyCompletedTodos || 0) + 1
                                    : (userData.weeklyCompletedTodos || 0) - 1;

                                // Update the user's points in Firestore
                               userData = {
                                   ...userData,
                                   weeklyPoints: weeklyPoints >= 0 ? weeklyPoints : 0,
                                   weeklyDayPoints: pointsPerDay,
                                   allTimePoints: allTimePoints >= 0 ? allTimePoints : 0,
                                   weeklyCompletedTodos: weeklyCompletedTodos >= 0 ? weeklyCompletedTodos : 0
                               }
                               userBatch.update(userRef, userData);
                            });
                        }

                        await firestore()
                            .collection("Todos")
                            .doc(todoData.id)
                            .update(todoData);

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

const getCurrentDay = () => {
    const days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
    const now = new Date();
    return days[now.getDay()];
};