import { FetchError } from "@medusajs/js-sdk"
import { HttpTypes } from "@medusajs/types"
import {
  QueryKey,
  useMutation,
  UseMutationOptions,
  useQuery,
  UseQueryOptions
} from "@tanstack/react-query"

import { sdk } from "../../lib/client"
import { queryClient } from "../../lib/query-client"
import { queryKeysFactory, TQueryKey } from "../../lib/query-key-factory"

const VIEWS_QUERY_KEY = "views" as const
const _viewsKeys = queryKeysFactory(VIEWS_QUERY_KEY) as TQueryKey<"views"> & {
  columns: (entity: string) => any
  active: (entity: string) => any
  configurations: (entity: string, query?: any) => any
}

_viewsKeys.columns = function(entity: string) {
  return [this.all, "columns", entity]
}

_viewsKeys.active = function(entity: string) {
  return [this.detail(entity), "active"]
}

_viewsKeys.configurations = function(entity: string, query?: any) {
  const key = [this.all, "configurations", entity]
  if (query !== undefined) {
    key.push(query)
  }
  return key
}

export const viewsQueryKeys = _viewsKeys

// Generic hook to get columns for any entity
export const useEntityColumns = (entity: string, options?: Omit<
  UseQueryOptions<
    HttpTypes.AdminViewsEntityColumnsResponse,
    FetchError,
    HttpTypes.AdminViewsEntityColumnsResponse,
    QueryKey
  >,
  "queryFn" | "queryKey"
>) => {
  const { data, ...rest } = useQuery({
    queryFn: () => sdk.admin.views.columns(entity),
    queryKey: viewsQueryKeys.columns(entity),
    ...options,
  })

  return { ...data, ...rest }
}

// View Configuration hooks

// List view configurations for an entity
export const useViewConfigurations = (
  entity: string,
  query?: HttpTypes.AdminGetViewConfigurationsParams,
  options?: Omit<
    UseQueryOptions<
      HttpTypes.AdminViewConfigurationListResponse,
      FetchError,
      HttpTypes.AdminViewConfigurationListResponse,
      QueryKey
    >,
    "queryFn" | "queryKey"
  >
) => {
  const { data, ...rest } = useQuery({
    queryFn: () => sdk.admin.views.listConfigurations(entity, query),
    queryKey: viewsQueryKeys.configurations(entity, query),
    ...options,
  })

  return { ...data, ...rest }
}

// Get active view configuration for an entity
export const useActiveViewConfiguration = (
  entity: string,
  options?: Omit<
    UseQueryOptions<
      HttpTypes.AdminViewConfigurationResponse & {
        active_view_configuration_id?: string | null
        is_default_active?: boolean
        default_type?: "system" | "code"
      },
      FetchError,
      HttpTypes.AdminViewConfigurationResponse & {
        active_view_configuration_id?: string | null
        is_default_active?: boolean
        default_type?: "system" | "code"
      },
      QueryKey
    >,
    "queryFn" | "queryKey"
  >
) => {
  const query = useQuery({
    queryFn: () => sdk.admin.views.retrieveActiveConfiguration(entity),
    queryKey: viewsQueryKeys.active(entity),
    ...options,
  })

  const { data, ...rest } = query

  return { ...data, ...rest }
}

// Get a specific view configuration
export const useViewConfiguration = (
  entity: string,
  id: string,
  query?: Record<string, any>,
  options?: Omit<
    UseQueryOptions<
      HttpTypes.AdminViewConfigurationResponse,
      FetchError,
      HttpTypes.AdminViewConfigurationResponse,
      QueryKey
    >,
    "queryFn" | "queryKey"
  >
) => {
  const { data, ...rest } = useQuery({
    queryFn: () => sdk.admin.views.retrieveConfiguration(entity, id, query),
    queryKey: viewsQueryKeys.detail(id, query),
    ...options,
  })

  return { ...data, ...rest }
}

// Create view configuration with toast notifications
export const useCreateViewConfiguration = (
  entity: string,
  options?: UseMutationOptions<
    HttpTypes.AdminViewConfigurationResponse,
    FetchError,
    HttpTypes.AdminCreateViewConfiguration
  >
) => {
  return useMutation({
    mutationFn: (payload: Omit<HttpTypes.AdminCreateViewConfiguration, "entity">) =>
      sdk.admin.views.createConfiguration(entity, payload),
    ...options,
    onSuccess: (data, variables, context) => {
      queryClient.invalidateQueries({ queryKey: viewsQueryKeys.configurations(entity) })
      // If set_active was true, also invalidate the active configuration
      if ((variables as any).set_active) {
        queryClient.invalidateQueries({
          queryKey: viewsQueryKeys.active(entity)
        })
      }
      options?.onSuccess?.(data, variables, context)
    },
  })
}

// Update view configuration
export const useUpdateViewConfiguration = (
  entity: string,
  id: string,
  options?: UseMutationOptions<
    HttpTypes.AdminViewConfigurationResponse,
    FetchError,
    HttpTypes.AdminUpdateViewConfiguration
  >
) => {
  return useMutation({
    mutationFn: (payload: HttpTypes.AdminUpdateViewConfiguration) =>
      sdk.admin.views.updateConfiguration(entity, id, payload),
    ...options,
    onSuccess: (data, variables, context) => {
      queryClient.invalidateQueries({ queryKey: viewsQueryKeys.configurations(entity) })
      queryClient.invalidateQueries({ queryKey: viewsQueryKeys.detail(id) })
      // Also invalidate active configuration if this view is currently active
      queryClient.invalidateQueries({ queryKey: viewsQueryKeys.active(entity) })
      options?.onSuccess?.(data, variables, context)
    },
  })
}

// Delete view configuration
export const useDeleteViewConfiguration = (
  entity: string,
  id: string,
  options?: UseMutationOptions<
    HttpTypes.AdminViewConfigurationDeleteResponse,
    FetchError,
    void
  >
) => {
  return useMutation({
    mutationFn: () => sdk.admin.views.deleteConfiguration(entity, id),
    ...options,
    onSuccess: (data, variables, context) => {
      queryClient.invalidateQueries({ queryKey: viewsQueryKeys.configurations(entity) })
      queryClient.invalidateQueries({ queryKey: viewsQueryKeys.detail(id) })
      // Also invalidate active configuration as it might have changed
      queryClient.invalidateQueries({
        queryKey: viewsQueryKeys.active(entity)
      })
      options?.onSuccess?.(data, variables, context)
    },
  })
}

// Set active view configuration
export const useSetActiveViewConfiguration = (
  entity: string,
  options?: UseMutationOptions<
    { success: boolean },
    FetchError,
    string | null
  >
) => {
  return useMutation({
    mutationFn: (viewConfigurationId: string | null) => {
      return sdk.admin.views.setActiveConfiguration(entity, {
        view_configuration_id: viewConfigurationId
      })
    },
    ...options,
    onSuccess: async (data, variables, context) => {
      // Invalidate active configuration
      await queryClient.invalidateQueries({
        queryKey: viewsQueryKeys.active(entity)
      })
      // Also invalidate the list as the active status might be shown there
      await queryClient.invalidateQueries({ queryKey: viewsQueryKeys.configurations(entity) })
      options?.onSuccess?.(data, variables, context)
    },
    onError: (error, variables, context) => {
      options?.onError?.(error, variables, context)
    },
  })
}
