import { __ } from "@wordpress/i18n";
import { keepPreviousData, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import type { QueryClient, UseQueryOptions } from "@tanstack/react-query";
import { useCallback, useState } from "react";
import { apiErrorMessage, wpDelete, wpGet, wpPost } from "./client";
import { showAdminNotice } from "../components/common";
import type {
  ProductHistoryQuery,
  ProductHistoryResponse,
  ProductListQuery,
  ProductListProduct,
  ProductListResponse,
} from "../features/products/components/productTypes";
import type {
  ActionResponse,
  ImportOrdersResponse,
  HomeResponse,
  MarketplaceOrder,
  ProductStatsResponse,
  SaleChannelForm,
  SaleChannelFormResponse,
  SaleChannelsResponse,
  SaleChannelTypesResponse,
  SettingsResponse,
  WooProductsResponse,
  OrdersResponse,
  OrderStatsResponse,
} from "../types";

type ConnectionResponse = Pick<SettingsResponse, "connection">;

export function useStoredPageState<State>(
  key: string,
  defaultState: State,
  normalizeState: (value: unknown) => State,
): [State, (state: State) => void] {
  const storageKey = `market-sync-page-state:${key}`;
  const [initialState] = useState<State>(() => {
    if (typeof window === "undefined") return defaultState;

    try {
      const storedValue = window.sessionStorage.getItem(storageKey);

      return normalizeState(storedValue ? JSON.parse(storedValue) : defaultState);
    } catch {
      return defaultState;
    }
  });

  const saveState = useCallback(
    (state: State) => {
      if (typeof window === "undefined") return;

      try {
        window.sessionStorage.setItem(storageKey, JSON.stringify(state));
      } catch {
        // Ignore storage failures; pages still work without persisted filters.
      }
    },
    [storageKey],
  );

  return [initialState, saveState];
}

export function useConnection(options: Partial<UseQueryOptions<ConnectionResponse, Error>> = {}) {
  return useQuery({
    queryKey: ["connection"],
    queryFn: () => wpGet<ConnectionResponse>("/admin/connection"),
    ...options,
  });
}

export function useHome() {
  return useQuery({
    queryKey: ["home"],
    queryFn: () => wpGet<HomeResponse>("/admin/home"),
    refetchOnWindowFocus: false,
    staleTime: 60 * 1000,
  });
}

export function useSettings() {
  return useQuery({
    queryKey: ["settings"],
    queryFn: () => wpGet<SettingsResponse>("/admin/settings"),
  });
}

export function useSaleChannels() {
  return useQuery({
    queryKey: ["sale-channels"],
    queryFn: () => wpGet<SaleChannelsResponse>("/admin/sale-channels"),
    staleTime: 60 * 1000,
  });
}

export function useSaleChannelTypes() {
  return useQuery({
    queryKey: ["sale-channel-types"],
    queryFn: () => wpGet<SaleChannelTypesResponse>("/admin/sale-channel-types"),
    staleTime: 5 * 60 * 1000,
  });
}

export function useSaleChannelForm(params: {
  channelType?: string;
  saleChannelId?: number | string | null;
}) {
  const query = new URLSearchParams();

  // Presence check, not truthiness: a sale channel id of 0 must still be sent
  // (dropping it would make the form endpoint return an "add" form and turn an
  // edit into a duplicate channel on save).
  const hasSaleChannelId =
    params.saleChannelId !== null &&
    params.saleChannelId !== undefined &&
    params.saleChannelId !== "";

  if (params.channelType) {
    query.set("channel_type", params.channelType);
  }

  if (hasSaleChannelId) {
    query.set("sale_channel_id", String(params.saleChannelId));
  }

  return useQuery({
    enabled: Boolean(params.channelType) || hasSaleChannelId,
    queryKey: ["sale-channel-form", params.channelType || "", params.saleChannelId ?? ""],
    queryFn: () => wpGet<SaleChannelFormResponse>(`/admin/sale-channels/form?${query}`),
    staleTime: 60 * 1000,
  });
}

export function useProductStats() {
  return useQuery({
    queryKey: ["products", "stats"],
    queryFn: () => wpGet<ProductStatsResponse>("/admin/products/stats"),
  });
}

export function useProducts(
  status: "linked" | "unlinked",
  params: ProductListQuery,
  enabled = true,
) {
  const query = new URLSearchParams();
  if (params.page > 1) query.set("page", String(params.page));
  if (params.saleChannelId) query.set("sales_channel_id", params.saleChannelId);
  if (params.search.trim()) query.set("search", params.search.trim());
  query.set("status", status);

  return useQuery({
    enabled,
    queryKey: ["products", status, params],
    queryFn: () => wpGet<ProductListResponse>(`/admin/products?${query}`),
  });
}

export function useProduct(productId: number | string) {
  return useQuery({
    enabled: String(productId) !== "",
    meta: { handlesNotFound: true },
    queryKey: ["products", "detail", productId],
    queryFn: () =>
      wpGet<ProductListProduct>(`/admin/products/${encodeURIComponent(String(productId))}`),
  });
}

export function useSaveProductTax() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (data: { product_ids: Array<number | string>; tax: number }) =>
      wpPost<ActionResponse, typeof data>("/admin/products/tax", data),
    onSuccess: async () => {
      await queryClient.invalidateQueries({ queryKey: ["products"] });
    },
  });
}

export function useProductHistory(
  kind: "inventory" | "price",
  params: ProductHistoryQuery,
  enabled = true,
) {
  const path = kind === "price" ? "/admin/products/price-history" : "/admin/products/history";
  const query = new URLSearchParams();
  if (params.saleChannelId) query.set("sales_channel_id", params.saleChannelId);
  const queryString = query.toString();

  return useQuery({
    enabled,
    queryKey: ["products", `${kind}-history`, params],
    queryFn: () => wpGet<ProductHistoryResponse>(`${path}${queryString ? `?${queryString}` : ""}`),
  });
}

export function useWooProducts(search: string) {
  const query = new URLSearchParams();
  if (search.trim()) query.set("search", search.trim());
  const queryString = query.toString();

  return useQuery({
    queryKey: ["woo-products", search.trim()],
    queryFn: () =>
      wpGet<WooProductsResponse>(
        `/admin/products/woocommerce${queryString ? `?${queryString}` : ""}`,
      ),
    staleTime: 30 * 1000,
  });
}

export function useOrders(
  page: number,
  search: string,
  saleChannelId?: string,
  importStatus?: string,
  archivedStatus?: string,
  trackingStatus?: string,
  enabled = true,
) {
  const query = new URLSearchParams();

  if (page > 1) query.set("page", String(page));
  if (search.trim()) query.set("search", search.trim());
  if (saleChannelId) query.set("sales_channel_id", saleChannelId);
  if (importStatus) query.set("import_status", importStatus);
  if (archivedStatus) query.set("archived_status", archivedStatus);
  if (trackingStatus) query.set("tracking_status", trackingStatus);

  const queryString = query.toString();

  return useQuery({
    enabled,
    placeholderData: keepPreviousData,
    queryKey: [
      "orders",
      page,
      search.trim(),
      saleChannelId ?? "",
      importStatus ?? "",
      archivedStatus ?? "",
      trackingStatus ?? "",
    ],
    queryFn: () => wpGet<OrdersResponse>(`/admin/orders${queryString ? `?${queryString}` : ""}`),
  });
}

export function useOrder(orderId: number | string) {
  return useQuery({
    enabled: String(orderId) !== "",
    meta: { handlesNotFound: true },
    queryKey: ["orders", "detail", orderId],
    queryFn: () => wpGet<MarketplaceOrder>(`/admin/orders/${encodeURIComponent(String(orderId))}`),
  });
}

export function useImportOrders() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (orders: Array<Pick<MarketplaceOrder, "id" | "order_number">>) =>
      wpPost<
        ImportOrdersResponse,
        { order_ids: Array<number | string>; order_numbers: Record<string, string> }
      >("/admin/orders/import", {
        order_ids: orders.map((order) => order.id),
        order_numbers: Object.fromEntries(orders.map((order) => [order.id, order.order_number])),
      }),
    onSuccess: async () => {
      await queryClient.invalidateQueries({ queryKey: ["orders"] });
    },
  });
}

export function useOrderStats(saleChannelId?: string) {
  const query = new URLSearchParams();

  if (saleChannelId) query.set("sales_channel_id", saleChannelId);

  const queryString = query.toString();

  return useQuery({
    queryKey: ["orders", "stats", saleChannelId ?? ""],
    queryFn: () =>
      wpGet<OrderStatsResponse>(`/admin/orders/stats${queryString ? `?${queryString}` : ""}`),
  });
}

export function useArchiveOrders() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (orderIds: Array<number | string>) =>
      wpPost<ActionResponse, { order_ids: Array<number | string> }>("/admin/orders/archive", {
        order_ids: orderIds,
      }),
    onSuccess: async (data) => {
      showAdminNotice(
        data.message || __("Order(s) archived successfully.", "market-sync"),
        "success",
      );
      await Promise.all([
        queryClient.invalidateQueries({ queryKey: ["orders"] }),
        queryClient.invalidateQueries({ queryKey: ["home"] }),
      ]);
    },
    onError: (error) => {
      showAdminNotice(
        apiErrorMessage(error) || __("Failed to archive order(s).", "market-sync"),
        "error",
      );
    },
  });
}

const invalidateProductData = async (queryClient: QueryClient) => {
  await Promise.all([
    queryClient.invalidateQueries({ queryKey: ["orders"] }),
    queryClient.invalidateQueries({ queryKey: ["products"] }),
    queryClient.invalidateQueries({ queryKey: ["home"] }),
  ]);
};

export function useUnlinkProduct() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (productId: number | string) =>
      wpDelete<ActionResponse>(`/admin/products/${productId}/link`),
    onSuccess: () => invalidateProductData(queryClient),
  });
}

export interface LinkProductInput {
  inventory_quantity: number;
  platform_product_id: number;
  product_id: number;
  title: string;
  variant_id: number;
}

export function useLinkProduct() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (data: LinkProductInput) =>
      wpPost<ActionResponse, LinkProductInput>("/admin/products/link", data),
    onSuccess: () => invalidateProductData(queryClient),
  });
}

export function useSaveSaleChannel() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (form: SaleChannelForm) =>
      wpPost<ActionResponse, SaleChannelForm>("/admin/sale-channels", form),
    onSuccess: async () => {
      await Promise.all([
        queryClient.invalidateQueries({ queryKey: ["sale-channels"] }),
        queryClient.invalidateQueries({ queryKey: ["home"] }),
        // Refetch the edit form so reopening the modal shows the values the
        // server persisted, not the pre-save cache (staleTime keeps it 60s).
        queryClient.invalidateQueries({ queryKey: ["sale-channel-form"] }),
      ]);
    },
  });
}

export function useStartSaleChannelOAuth() {
  return useMutation({
    mutationFn: (form: SaleChannelForm) =>
      wpPost<ActionResponse & { url?: string }, SaleChannelForm>(
        "/admin/sale-channels/oauth",
        form,
      ),
  });
}

export function useDeleteSaleChannel() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: (saleChannelId: number | string) =>
      wpDelete<ActionResponse>(`/admin/sale-channels/${saleChannelId}`),
    onSuccess: async () => {
      await Promise.all([
        queryClient.invalidateQueries({ queryKey: ["sale-channels"] }),
        queryClient.invalidateQueries({ queryKey: ["home"] }),
      ]);
    },
  });
}

export function useCheckConnection() {
  const queryClient = useQueryClient();
  const [response, setResponse] = useState<ActionResponse | null>(null);

  const mutation = useMutation({
    mutationFn: () => wpPost<ActionResponse>("/admin/connection/check"),
    onMutate: () => setResponse(null),
    onSuccess: async (nextResponse) => {
      setResponse(nextResponse);
      await Promise.all([
        queryClient.invalidateQueries({ queryKey: ["connection"] }),
        queryClient.invalidateQueries({ queryKey: ["settings"] }),
        queryClient.invalidateQueries({ queryKey: ["home"] }),
      ]);
    },
  });

  return { ...mutation, response };
}

/**
 * Starts the first SaaS handshake. Only called from a Connect button click,
 * so the handshake itself makes no outbound request before the user consents.
 */
export function useConnect() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: () => wpPost<ActionResponse>("/admin/connection/connect"),
    onSuccess: async (response) => {
      if (response.ok) {
        await queryClient.invalidateQueries();
      }
    },
  });
}

export function useReauthorize() {
  const queryClient = useQueryClient();

  return useMutation({
    mutationFn: () => wpPost<ActionResponse>("/admin/connection/reauthorize"),
    onSuccess: async (response) => {
      if (response.ok) {
        await queryClient.invalidateQueries();
      }
    },
  });
}
