"use client";
import axiosInstanceClient from "@/utils/axiosClient";
import { AxiosError } from "axios";
import React, { useState, useEffect, useMemo } from "react";
import Page404 from "../ErrorPages/Page404";
import Page403 from "../ErrorPages/Page403";
import Page500 from "../ErrorPages/Page500";
import Page400 from "../ErrorPages/Page400";
import Page429 from "../ErrorPages/Page429";
import ShowAlertMixin from "../ShowAlertMixin";
import Loader from "../Loader/Loader";
import LoaderWrapper from "../Loader/LoaderWrapper";
import UseAuthorizationErrorClient from "@/hooks/UseAuthorizationErrorClient";

interface SingleRequest {
  url: string;
  params?: Record<string, any>;
}

interface MultiRequest {
  requests: Array<{
    url: string;
    key: string;
    params?: Record<string, any>;
  }>;
}

type GeneralClientAxiosProps = SingleRequest | MultiRequest;

function isMultiRequest(props: GeneralClientAxiosProps): props is MultiRequest {
  return "requests" in props;
}

export default function GeneralClientAxios({
  children,
  ...props
}: GeneralClientAxiosProps & {
  children: (
    data: any,
    refetch: () => void,
    loadingChildren: boolean,
    meta?: any,
  ) => React.ReactNode;
}) {
  const [data, setData] = useState<any>(null);
  const [meta, setMeta] = useState<any>(null);

  const [loading, setLoading] = useState<boolean>(true);
  const [refetchloading, setRefetchloading] = useState<boolean>(false);

  const [loadingChildren, setLoadingChildren] = useState<boolean>(false);

  const [error, setError] = useState<AxiosError | null>(null);

  // Memoize params to detect changes
  const paramsString = useMemo(() => {
    if (isMultiRequest(props)) {
      return JSON.stringify(
        props.requests.map((req) => ({ url: req.url, params: req.params })),
      );
    }
    return JSON.stringify({ url: props.url, params: props.params });
  }, [props]);

  const fetchData = async () => {
    setError(null);
    try {
      if (isMultiRequest(props)) {
        const responses = await Promise.all(
          props.requests.map(({ url, params }) => {
            const fullUrl = params ? addQueryParams(url, params) : url;
            return axiosInstanceClient.get(fullUrl);
          }),
        );

        const fetchedData = responses.reduce(
          (acc, response, index) => ({
            ...acc,
            [props.requests[index].key]: response.data.data,
          }),
          {},
        );
        const fetchedMeta = responses.reduce(
          (acc, response, index) => ({
            ...acc,
            [props.requests[index].key]: response.data.meta,
          }),
          {},
        );
        setData(fetchedData);
        setMeta(fetchedMeta);
      } else {
        const { url, params } = props;
        const fullUrl = params ? addQueryParams(url, params) : url;

        const { data } = await axiosInstanceClient.get(fullUrl);
        setData(data.data);
        setMeta(data.meta);
      }
    } catch (err) {
      const error = err as AxiosError;
      setError(error);
    } finally {
      setLoading(false);
      setLoadingChildren(false);
      setRefetchloading(false);
    }
  };

  useEffect(() => {
    setLoadingChildren(true);
    fetchData();
  }, [paramsString]);

  const refetch = () => {
    // setRefetchloading(true);
    setLoadingChildren(true);
    fetchData();
  };

  if (loading) return <LoaderWrapper />;

  if (refetchloading) {
    return (
      <div className="screen_loader h-[720px] relative inset-0 bg-transparent dark:bg-[#060818] z-[1] grid place-content-center animate__animated">
        <Loader />
      </div>
    );
  }

  if (error) {
    return (
      <>
        {error?.response?.status === 401 && (
          <UseAuthorizationErrorClient showError={true} />
        )}
        {error?.response?.status === 400 && <Page400 />}
        {error?.response?.status === 403 && <Page403 />}
        {error?.response?.status === 404 && <Page404 />}
        {error?.response?.status === 429 && <Page429 />}
        {error?.response?.status === 500 && <Page500 />}
      </>
    );
  }

  return children(data, refetch, loadingChildren, meta);
}

function addQueryParams(url: string, params?: Record<string, any>): string {
  if (!params) return url;
  const query = new URLSearchParams(params as any).toString();
  return query ? `${url}?${query}` : url;
}
