import type { UseQueryResult } from '@tanstack/react-query'
import type {
  AddFilterOptions,
  FormulaRequestOptions,
  CategoryRequestOptions,
  TimeSeriesRequestOptions,
  HistogramRequestOptions,
  AggregationsRequestOptions,
  RangeRequestOptions,
  ScatterRequestOptions,
  TableRequestOptions,
  FeaturesRequestOptions,
} from '@carto/api-client'
import type { UseQueryOptions } from '@tanstack/react-query'

/**
 * Helper type for multi-value support in Formula widget props.
 * Formula has: column (optional), operationExp (optional)
 *
 * @since 4.6.0
 */
export type FormulaWidgetProps = Omit<
  FormulaRequestOptions,
  'filters' | 'column' | 'operationExp'
> & {
  column?: string | string[]
  operationExp?: string | string[]
}

/**
 * Helper type for multi-value support in Category widget props.
 * Category has: column (required), operationExp (optional), operationColumn (optional)
 *
 * @since 4.6.0
 */
export type CategoryWidgetProps = Omit<
  CategoryRequestOptions,
  'filters' | 'column' | 'operationExp' | 'operationColumn'
> & {
  column: string | string[]
  operationExp?: string | string[]
  operationColumn?: string | string[]
}

/**
 * Helper type for multi-value support in TimeSeries widget props.
 * TimeSeries has: column (required), operationExp (optional), operationColumn (optional)
 *
 * @since 4.6.0
 */
export type TimeSeriesWidgetProps = Omit<
  TimeSeriesRequestOptions,
  'filters' | 'column' | 'operationExp' | 'operationColumn'
> & {
  column: string | string[]
  operationExp?: string | string[]
  operationColumn?: string | string[]
}

/**
 * Helper type for multi-value support in Histogram widget props.
 * Histogram has: column (required), NO operationExp, NO operationColumn
 *
 * @since 4.6.0
 */
export type HistogramWidgetProps = Omit<
  HistogramRequestOptions,
  'filters' | 'column'
> & {
  column: string | string[]
}

/**
 * Helper type for multi-value support in Aggregations widget props.
 * Aggregations has: aggregations (array/string), NO column, NO operationExp
 *
 * @since 4.6.0
 */
export type AggregationsWidgetProps = Omit<
  AggregationsRequestOptions,
  'filters'
>

/**
 * Helper type for multi-value support in Range widget props.
 * Range has: column (required), NO operationExp, NO operationColumn
 *
 * @since 4.6.0
 */
export type RangeWidgetProps = Omit<
  RangeRequestOptions,
  'filters' | 'column'
> & {
  column: string | string[]
}

/**
 * Helper type for multi-value support in Spread widget props.
 * Spread has: column (required), NO operationExp, NO operationColumn
 * Uses Range API internally to calculate spread (max - min)
 *
 * @since 4.6.0
 */
export type SpreadWidgetProps = Omit<
  RangeRequestOptions,
  'filters' | 'column'
> & {
  column: string | string[]
}

/**
 * Helper type for multi-value support in Scatter widget props.
 * Scatter has: xColumn, yColumn (both required), NO operationExp
 *
 * @since 4.6.0
 */
export type ScatterWidgetProps = Omit<
  ScatterRequestOptions,
  'filters' | 'xColumn' | 'yColumn'
> & {
  xColumn: string | string[]
  yColumn: string | string[]
}

/**
 * Helper type for multi-value support in Table widget props.
 * Table has: columns (optional array), NO operationExp
 *
 * @since 4.6.0
 */
export type TableWidgetProps = Omit<TableRequestOptions, 'filters'>

/**
 * Helper type for multi-value support in Features widget props.
 * Features has: NO column, NO operationExp
 *
 * @since 4.6.0
 */
export type FeaturesWidgetProps = Omit<FeaturesRequestOptions, 'filters'>

/**
 * @deprecated Use specific widget props types (FormulaWidgetProps, CategoryWidgetProps, etc.) instead.
 * This generic type assumes all widgets have the same properties, which is incorrect.
 * @since 4.5.0
 */
export type WidgetPropsWithMultiColumn<T> = Omit<
  T,
  'filters' | 'column' | 'operationExp' | 'operationColumn'
> & {
  column?: string | string[]
  operationExp?: string | string[]
  operationColumn?: string | string[]
}

/**
 * Props for CARTO model components and hooks.
 *
 * @template W - Widget-specific props type (FormulaWidgetProps, CategoryWidgetProps, etc.)
 * @template R - Widget response data type
 *
 * @remarks
 * All CARTO model components (FormulaModel, CategoriesModel, etc.) use these props.
 * Supports both single-source and multi-source queries with flexible column configuration.
 *
 * @example
 * ```tsx
 * Single source (deprecated)
 * <FormulaModel
 *   accessToken={token}
 *   sourceId="sales"
 *   widgetProps={{ column: 'revenue', operation: 'sum' }}
 * />
 *
 * Multiple sources (recommended)
 * <FormulaModel
 *   accessToken={token}
 *   sourcesId={['sales_2023', 'sales_2024']}
 *   widgetProps={{ column: 'revenue', operation: 'sum' }}
 * />
 *
 * Multiple sources with different columns
 * <FormulaModel
 *   accessToken={token}
 *   sourcesId={['sales', 'inventory', 'customers']}
 *   widgetProps={{
 *     column: ['total_sales', 'stock_count', 'active_users'],
 *     operation: 'sum'
 *   }}
 * />
 * ```
 *
 * @since 4.6.0 - Changed to use specific widget props types
 */
export type ModelProps<W, R> = {
  /** CARTO API access token for authentication */
  accessToken: string
  /** Widget-specific configuration with multi-value support for applicable properties */
  widgetProps: W
  /** Optional additional filters to apply to the query */
  additionalFilter?: AddFilterOptions[] | AddFilterOptions[][]
  /** React Query configuration options */
  useQueryProps?: Omit<UseQueryOptions<R>, 'queryKey' | 'queryFn'>
} & (
  | {
      /**
       * @deprecated Use `sourcesId` instead. Will be removed in v5.0.0.
       * @see {@link sourcesId}
       */
      sourceId: string
      /**
       * Array of source identifiers for multi-source queries (recommended).
       * @since 4.0.0
       */
      sourcesId?: string[]
    }
  | {
      /**
       * @deprecated Use `sourcesId` instead. Will be removed in v5.0.0.
       * @see {@link sourcesId}
       */
      sourceId?: string
      /**
       * Array of source identifiers for multi-source queries (recommended).
       * @since 4.0.0
       */
      sourcesId: string[]
    }
)

export type ModelResponse<T = []> = UseQueryResult<T, Error>

/**
 * Conditional return type for model hooks (`useFormula`, `useCategories`, …).
 * Mirrors the `ModelProps` discriminated union: when the caller passes
 * `sourceId` (single-source), the response data is `R`; when only `sourcesId`
 * is passed (multi-source), it is `R[]`.
 *
 * Lives here so each per-model wrapper (see `formula.tsx`, `categories.tsx`,
 * …) can express the signature in a single line instead of inlining the
 * conditional twice (once for `useXxx`, once for the `XxxModel` children
 * render-prop).
 */
export type ModelHookResponse<P, R> = P extends {
  sourceId: string
  sourcesId?: string[]
}
  ? ModelResponse<R>
  : ModelResponse<R[]>

/**
 * Props for the render-props `XxxModel` components. Composes `ModelProps`
 * with a `children` callback receiving the same conditional response type
 * the corresponding `useXxx` hook returns.
 */
export type ModelComponentProps<
  W,
  R,
  P extends ModelProps<W, R> = ModelProps<W, R>,
> = P & {
  children: (result: ModelHookResponse<P, R>) => React.ReactNode
}
