/**
 * Render-hook coverage for the four React hooks exported by the source store:
 * useSource, useSources, useFilters (string + array overloads), and
 * useSourceWithFilters.
 *
 * The existing store.test.ts is extensive but uses `useSourceStore.getState()`
 * imperatively — none of these four hooks' bodies are exercised. This file
 * fills that gap so the `useShallow` selector branches and the
 * `useSourceWithFilters` useMemo branch (`if (!source) return undefined`) are
 * covered.
 */
import { describe, it, expect, beforeEach } from 'vitest'
import { renderHook } from '@testing-library/react'
import { FilterType, type AddFilterOptions } from '@carto/api-client'

import {
  useSourceStore,
  useSource,
  useSources,
  useFilters,
  useSourceWithFilters,
} from './store'
import type { AllExternalSources, Source } from './types'

beforeEach(() => {
  useSourceStore.setState({ sources: {}, filters: {} })
})

const querySource: Partial<Source<AllExternalSources>> = {
  type: 'query',
  data: 'SELECT 1',
  connectionName: 'conn',
}

const categoryFilter: AddFilterOptions[] = [
  { column: 'category', type: FilterType.IN, values: ['A', 'B'] },
]

describe('useSource', () => {
  it('returns the source when it exists', () => {
    useSourceStore.getState().setSource('h1', querySource)
    const { result } = renderHook(() => useSource('h1'))
    expect(result.current?.data).toBe('SELECT 1')
  })

  it('returns undefined when the id is unknown', () => {
    const { result } = renderHook(() => useSource('missing'))
    expect(result.current).toBeUndefined()
  })
})

describe('useSources', () => {
  it('returns only the sources that exist (filters out undefined)', () => {
    useSourceStore.getState().setSource('s1', querySource)
    useSourceStore.getState().setSource('s2', querySource)
    const { result } = renderHook(() => useSources(['s1', 'missing', 's2']))
    expect(result.current).toHaveLength(2)
  })

  it('returns an empty array when none exist', () => {
    const { result } = renderHook(() => useSources(['a', 'b']))
    expect(result.current).toEqual([])
  })
})

describe('useFilters', () => {
  it('string id overload returns the filters for that id', () => {
    useSourceStore.getState().setFilters('f1', categoryFilter)
    const { result } = renderHook(() => useFilters('f1'))
    // Type assertion: string overload returns Filters | undefined
    expect((result.current as { category?: unknown })?.category).toBeDefined()
  })

  it('string id overload returns undefined when no filters set', () => {
    const { result } = renderHook(() => useFilters('none'))
    expect(result.current).toBeUndefined()
  })

  it('array overload returns Filters per id (Array.isArray branch)', () => {
    useSourceStore.getState().setFilters('f1', categoryFilter)
    const { result } = renderHook(() => useFilters(['f1', 'missing']))
    expect(Array.isArray(result.current)).toBe(true)
    expect(result.current).toHaveLength(2)
  })
})

describe('useSourceWithFilters', () => {
  it('returns merged source + filters when both exist', () => {
    useSourceStore.getState().setSource('mw1', querySource)
    useSourceStore.getState().setFilters('mw1', categoryFilter)
    const { result } = renderHook(() => useSourceWithFilters('mw1'))
    expect(result.current).toBeDefined()
    expect(result.current?.data).toBe('SELECT 1')
    expect(result.current?.filters).toBeDefined()
  })

  it('returns source with empty filters when filters are absent (filters ?? {} branch)', () => {
    useSourceStore.getState().setSource('mw2', querySource)
    const { result } = renderHook(() => useSourceWithFilters('mw2'))
    expect(result.current).toBeDefined()
    expect(result.current?.filters).toEqual({})
  })

  it('returns undefined when the source does not exist', () => {
    const { result } = renderHook(() => useSourceWithFilters('does-not-exist'))
    expect(result.current).toBeUndefined()
  })
})
