import { useMutation, useQuery } from "@tanstack/react-query";
import { queryClient, toast } from "@xtablo/shared";
import { Database } from "@xtablo/shared/types/database.types";
import { useEffect, useState } from "react";
import { supabase } from "../lib/supabase";
import { useUser } from "../providers/UserStoreProvider";

export type TimeRange = {
  start: string;
  end: string;
};

export type DayAvailability = {
  enabled: boolean;
  timeRanges: TimeRange[];
};

export type WeeklyAvailability = {
  [key: number]: DayAvailability;
};

export type Exception = {
  date: string;
} & (
  | {
      type: "hours";
      hours: TimeRange[];
    }
  | {
      type: "day";
    }
);

const DAYS_OF_WEEK = [0, 1, 2, 3, 4, 5, 6];

export const DEFAULT_AVAILABILITIES: WeeklyAvailability = DAYS_OF_WEEK.reduce((acc, day) => {
  if (day === 5 || day === 6) {
    acc[day] = {
      enabled: false,
      timeRanges: [{ start: "09:00", end: "17:00" }],
    };
  } else {
    acc[day] = {
      enabled: true,
      timeRanges: [{ start: "09:00", end: "17:00" }],
    };
  }
  return acc;
}, {} as WeeklyAvailability);

export function useAvailabilities() {
  const user = useUser();
  const { data: availabilities, isLoading } = useQuery<
    Database["public"]["Tables"]["availabilities"]["Row"]
  >({
    queryKey: ["availabilities"],
    queryFn: async () => {
      const { data, error } = await supabase
        .from("availabilities")
        .select("*")
        .eq("user_id", user.id)
        .limit(1);
      if (error) throw error;
      return data?.[0] as Database["public"]["Tables"]["availabilities"]["Row"];
    },
    enabled: !!user.id,
  });

  const { mutate: updateAvailabilities } = useMutation<
    void,
    Error,
    {
      updatedAvailabilities: WeeklyAvailability;
      newException?: Exception | null;
    }
  >({
    mutationFn: async ({
      updatedAvailabilities,
      newException = null,
    }: {
      updatedAvailabilities: WeeklyAvailability;
      newException?: Exception | null;
    }) => {
      const newAvailabilities = updatedAvailabilities;
      const newExceptions = (availabilities?.exceptions as Exception[] | null) || [];
      if (newException) {
        newExceptions.push(newException);
      }
      const { error } = await supabase.from("availabilities").upsert(
        {
          availability_data: newAvailabilities,
          exceptions: newExceptions,
          user_id: user.id,
        },
        {
          onConflict: "user_id",
        }
      );
      if (error) throw error;
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["availabilities"] });
      toast.add({
        title: "Succès",
        description: "Disponibilités mises à jour avec succès",
        type: "success",
      });
    },
    onError: () => {
      toast.add({
        title: "Erreur",
        description: "Erreur lors de la mise à jour des disponibilités",
        type: "error",
      });
    },
  });

  const { mutate: deleteException } = useMutation<void, Error, { exceptionIndex: number }>({
    mutationFn: async ({ exceptionIndex }: { exceptionIndex: number }) => {
      const currentExceptions = (availabilities?.exceptions as Exception[] | null) || [];
      const updatedExceptions = currentExceptions.filter((_, index) => index !== exceptionIndex);

      const { error } = await supabase.from("availabilities").upsert(
        {
          availability_data: availabilities?.availability_data || DEFAULT_AVAILABILITIES,
          exceptions: updatedExceptions,
          user_id: user.id,
        },
        {
          onConflict: "user_id",
        }
      );
      if (error) throw error;
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["availabilities"] });
      toast.add({
        title: "Succès",
        description: "Exception supprimée avec succès",
        type: "success",
      });
    },
  });

  const [draftAvailabilities, setDraftAvailabilities] = useState<WeeklyAvailability | null>(null);

  useEffect(() => {
    if (availabilities?.availability_data) {
      setDraftAvailabilities(availabilities.availability_data as WeeklyAvailability);
    }
  }, [availabilities?.availability_data]);

  return {
    isLoading,
    updateAvailabilities,
    draftAvailabilities: draftAvailabilities || DEFAULT_AVAILABILITIES,
    setDraftAvailabilities,
    exceptions: (availabilities?.exceptions as Exception[] | null) || [],
    deleteException,
    isModified: draftAvailabilities !== availabilities?.availability_data,
  };
}
