import { useMutation, useQuery } from "@tanstack/react-query";
import type { NPEDFieldType } from "../types/types";
import { useIntegrationsContext } from "../context/IntegrationsContext";
import { useEffect } from "react";
import { CAM_BASE } from "../utils/config";
import { toast } from "sonner";

async function fetchNPEDDetails() {
  const fetchUrl = `${CAM_BASE}/api/fetch-config?id=NPED`;
  const response = await fetch(fetchUrl, {
    signal: AbortSignal.timeout(300000),
  });
  if (!response.ok) throw new Error("Cannot reach fetch-config endpoint");

  return response.json();
}

async function signIn(loginDetails: NPEDFieldType) {
  const { frontId, rearId, username, password, clientId } = loginDetails;

  const NPEDLoginURLFront = `${CAM_BASE}/api/update-config?id=${frontId}`;
  const NPEDLoginURLRear = `${CAM_BASE}/api/update-config?id=${rearId}`;

  const payload = (id: string) => ({
    id,
    fields: [
      { property: "propEnabled", value: true },
      { property: "propUsername", value: username },
      { property: "propPassword", value: password },
      { property: "propClientID", value: clientId },
    ],
  });

  const [frontRes, rearRes] = await Promise.all([
    fetch(NPEDLoginURLFront, {
      method: "POST",
      body: JSON.stringify(payload(frontId)),
    }),
    fetch(NPEDLoginURLRear, {
      method: "POST",
      body: JSON.stringify(payload(rearId)),
    }),
  ]);

  if (!frontRes.ok || !rearRes.ok) throw new Error("Cannot reach NPED endpoint");

  return {
    frontResponse: frontRes.json(),
    rearResponse: rearRes.json(),
  };
}

async function signOut() {
  const nullPayload = {
    id: "NPED",
    fields: [
      { property: "propEnabled", value: false },
      { property: "propUsername", value: "" },
      { property: "propPassword", value: "" },
      { property: "propClientID", value: "" },
    ],
  };
  const NPEDLoginURLFront = `${CAM_BASE}/api/update-config?id=NPED`;
  const response = await fetch(NPEDLoginURLFront, {
    method: "POST",
    body: JSON.stringify(nullPayload),
  });

  if (!response.ok) throw new Error("cannot reach NPED sign out endpoint");

  return response.json();
}

export const useNPEDAuth = () => {
  const { dispatch } = useIntegrationsContext();

  const signInMutation = useMutation({
    mutationKey: ["NPEDSignin"],
    mutationFn: signIn,
    onMutate: () => {
      toast.loading("Signing in...");
    },
    onSuccess: async (data) => {
      toast.dismiss();
      toast.success("Signed in successfully!");

      dispatch({ type: "LOGIN", payload: await data.frontResponse });
    },
    onError: (error) => {
      toast.dismiss();
      if (error.message.includes("timed out")) {
        toast.error("Connection timed out. Please check your network.");
      } else {
        toast.error(`Sign-in failed: ${error.message}`);
      }
    },
  });

  const signOutMutation = useMutation({
    mutationKey: ["auth", "NPEDSignOut"],
    mutationFn: signOut,
    onSuccess: () => {
      toast.success("Signed out successfully");
      dispatch({ type: "LOGOUT", payload: null });
    },
    onError: (error) => {
      toast.error(`Sign-out failed: ${error.message}`);
    },
  });

  const fetchdataQuery = useQuery({
    queryKey: ["auth", "NPEDFetch"],
    queryFn: fetchNPEDDetails,
  });

  useEffect(() => {
    if (fetchdataQuery.isSuccess && fetchdataQuery.data) {
      dispatch({ type: "LOGIN", payload: fetchdataQuery.data });
    } else {
      dispatch({ type: "LOGOUT", payload: null });
    }
  }, [dispatch, fetchdataQuery.data, fetchdataQuery.isSuccess]);

  useEffect(() => {
    if (fetchdataQuery.isError) toast.error(fetchdataQuery.error.message);
  }, [fetchdataQuery?.error?.message, fetchdataQuery.isError]);

  return {
    signIn: signInMutation.mutate,
    signInAsync: signInMutation.mutateAsync,
    isPending: signInMutation.isPending,
    isError: signInMutation.isError,
    error: signInMutation.error,
    data: signInMutation.data,
    fetchdataQueryError: fetchdataQuery.error,
    fetchdataQueryLoading: fetchdataQuery.isLoading,
    signOut: signOutMutation.mutate,
  };
};
