import type { RangeRequestOptions, RangeResponse } from '@carto/api-client'
import { createModel, type ModelQueryFactory } from './utils/create-model'
import { getModelQueryOptions } from './utils/get-model-query-options'
import { useSourceSlices } from './utils/use-source-slices'
import type {
  ModelComponentProps,
  ModelHookResponse,
  ModelProps,
  RangeWidgetProps,
} from './types'

export const getRange: ModelQueryFactory<RangeWidgetProps, RangeResponse> = (
  args,
) =>
  getModelQueryOptions<RangeWidgetProps, RangeResponse>({
    queryKeyPrefix: ['range'],
    getWidgetMethod: (widgetModel) => (params) =>
      widgetModel.getRange(params as RangeRequestOptions),
    ...args,
  })

const { useModelHook: useRangeQuery } = createModel<
  RangeWidgetProps,
  RangeResponse
>({ buildQuery: getRange })

/**
 * `useRange` is a hook that retrieves the minimum and maximum values for a numerical column, enabling range-based filtering.
 * `RangeModel` is the render-props component equivalent.
 *
 * @example
 * ```tsx
 * <RangeModel
 *   accessToken={token}
 *   sourceId="my_source"
 *   widgetProps={{ column: 'price' }}
 * >
 *   {({ data }) => <RangeSlider min={data?.min} max={data?.max} />}
 * </RangeModel>
 * ```
 */
function useRange<P extends ModelProps<RangeWidgetProps, RangeResponse>>(
  props: P,
): ModelHookResponse<P, RangeResponse> {
  const { sourceId, sourcesId } = props
  const slices = useSourceSlices(sourceId ? [sourceId] : (sourcesId ?? []))
  return useRangeQuery(props, slices)
}

function RangeModel<P extends ModelProps<RangeWidgetProps, RangeResponse>>(
  props: ModelComponentProps<RangeWidgetProps, RangeResponse, P>,
): React.ReactElement {
  return props.children(useRange(props)) as React.ReactElement
}

export { useRange, RangeModel }
