import { type RefetchOptions, useQueries } from "@tanstack/react-query";

import type {
  Input,
  Output,
  RequestStatusEnum,
  RouteDetails,
  STATUS_CODE,
} from "@/types/index";
import { useConfig } from "@hooks/useConfig";
import { bungeeApiFetcher } from "@utils/fetcher";
import type {
  ManualRefuel,
  OrderFlowType,
  RequestType,
  Rewards,
  TxData,
} from "../common/quote/types";

type QueryResult = {
  data: {
    requests: AutoOrderData[];
    totalRequests: number;
  };
};

export const useAutoHistory = ({
  userAddresses,
  pageSize,
  pageNumber,
}: {
  userAddresses: (string | undefined)[];
  pageSize: number;
  pageNumber: number;
}) => {
  const { apiKey, baseUrl } = useConfig();

  return useQueries({
    queries: userAddresses.map((userAddress) => ({
      queryKey: ["bungee-order-history", apiKey, userAddress, pageNumber],
      queryFn: async () => {
        const query = `${baseUrl}/bungee-auto/history?sender=${userAddress}&pageSize=${pageSize}&pageNumber=${pageNumber}`;
        const response = await bungeeApiFetcher<{ result: QueryResult }>(
          query,
          apiKey
        );
        return response.result.data;
      },
      enabled: !!userAddress,
      refetchOnWindowFocus: false,
      retry: 2,
      staleTime: 10000,
    })),

    combine: (queries) => {
      const formattedData = queries
        .flatMap((d) => d.data?.requests || [])
        .map((item) => {
          // calculating the swap time (in seconds)
          const timeDiffInSeconds = item.destTimestamp
            ? item.destTimestamp - item.srcTimestamp
            : 0;

          return {
            ...item,
            primaryInput: item.input?.[0],
            primaryOutput: item.output?.[0],
            swapTime: timeDiffInSeconds,
            isSwapRoute: item.requestType === "SWAP_REQUEST",
            routingMode: "auto",
          } as AutoOrderData;
        });
      return {
        error: queries.find((d) => d.isError)?.error.message,
        isError: queries.some((d) => d.isError),
        isLoading: queries.some((d) => d.isLoading),
        isSuccess: queries.every((d) => d.isSuccess),
        data: formattedData,
        totalPages: Math.ceil(
          queries.reduce((acc, d) => acc + (d.data?.totalRequests || 0), 0) /
            (pageSize * queries.length) // If we have 2 users, and each user has 100 requests, and pageSize is 10, then we have 200 requests in total. So totalPages is `200 / (10 * 2) = 10`.
        ),
        refetch: (options?: RefetchOptions) =>
          Promise.all(queries.map((d) => d.refetch(options))),
      };
    },
  });
};

export interface BaseOrderData {
  routingMode: "auto" | "manual";
  input: Input[];
  output: Output[];
  orderTimestamp: number;
  srcTimestamp: number;
  destTimestamp?: number;
  statusCode: STATUS_CODE;
  sender: string;
  receiver: string;
  requestHash: string; // derived for manual

  // derived
  status: keyof typeof RequestStatusEnum;
  swapTime: number;
  primaryInput: Input;
  primaryOutput: Output;
  isSwapRoute: boolean;
  flowType: OrderFlowType;
}

export interface AutoOrderData extends BaseOrderData {
  routingMode: "auto";
  txData: TxData | null;
  requestType: RequestType;
  quoteId: string;
  rewards?: Rewards;
  slippage: number | null;
  suggestedClientSlippage?: number;
  batchId?: string; // used to check batching status. not replacing requestHash with batching id, as requestHash is still needed to check the status
}

export interface ManualOrderData extends BaseOrderData {
  routingMode: "manual";
  routeId: string;
  protocol: RouteDetails;
  estimatedFulfilTime: number;
  refuel: ManualRefuel | null;
  slippage: number;
  batchId?: string; // not using atm. note: requestHash is replaced with batching id for manual
}

export type OrderData = AutoOrderData | ManualOrderData;
