import { useMemo } from 'react'
import { useSources } from '../../providers/sources/store'

// Type for the widget model returned by sources
type SourceWidget = ReturnType<typeof useSources>[0]['widgets']
type WidgetModelResult = SourceWidget | null

interface SingleSourceWidgetArgs {
  accessToken: string
  sourceId: string
  sourcesId?: never
}

interface MultiSourceWidgetArgs {
  accessToken: string
  sourceId?: never
  sourcesId: string[]
}

/**
 * Resolves the CARTO widget model for one or more data sources, configuring the access token for API communication.
 *
 * @remarks
 * Supports two calling patterns: positional arguments `useWidgetModel(accessToken, sourceId)` and an object argument
 * `useWidgetModel({ accessToken, sourceId })`. When a single `sourceId` is provided, returns a single widget model (or null).
 * When `sourcesId` (array) is provided, returns an array of widget models.
 */
// Overloads for single source (returns single widget model or null)
export function useWidgetModel(
  accessToken: string,
  sourceId: string,
): WidgetModelResult

// Overload for multi-source (returns array of widget models)
export function useWidgetModel(
  accessToken: string,
  sourcesId: string[],
): WidgetModelResult[]

// Overload for args object pattern (single source)
export function useWidgetModel(args: SingleSourceWidgetArgs): WidgetModelResult

// Overload for args object pattern (multi-source)
export function useWidgetModel(args: MultiSourceWidgetArgs): WidgetModelResult[]

export function useWidgetModel(
  accessTokenOrArgs: string | SingleSourceWidgetArgs | MultiSourceWidgetArgs,
  sourcesIdOrUndefined?: string | string[],
): WidgetModelResult | WidgetModelResult[] {
  // Handle both calling patterns: function args and object args
  const { accessToken, sourceId, sourcesId } = useMemo(() => {
    if (typeof accessTokenOrArgs === 'string') {
      // Legacy function signature: useWidgetModel(accessToken, sourcesId)
      return {
        accessToken: accessTokenOrArgs,
        sourceId:
          typeof sourcesIdOrUndefined === 'string'
            ? sourcesIdOrUndefined
            : undefined,
        sourcesId: Array.isArray(sourcesIdOrUndefined)
          ? sourcesIdOrUndefined
          : undefined,
      }
    } else {
      // New object signature: useWidgetModel({ accessToken, sourceId/sourcesId })
      return accessTokenOrArgs
    }
  }, [accessTokenOrArgs, sourcesIdOrUndefined])

  // Normalize to array format for consistent processing
  const isSingleSource = !!sourceId
  const sourcesArray = useMemo(() => {
    const array = isSingleSource ? [sourceId] : sourcesId
    if (!array) {
      throw new Error('Either sourceId or sourcesId must be provided')
    }
    return array
  }, [isSingleSource, sourceId, sourcesId])

  const sources = useSources(sourcesArray)

  const widgetModels = useMemo(() => {
    return sources.map((source) => {
      const widgetModel = source.widgets
      if (!widgetModel || !accessToken) {
        return null
      }

      // Set the access token directly on the widget model
      widgetModel.props.accessToken = accessToken
      return widgetModel
    })
  }, [accessToken, sources])

  // Return appropriate format based on input type
  if (isSingleSource) {
    return widgetModels[0]
  }

  return widgetModels
}
