import { omit } from 'lodash'
import { createContext, useContext, useEffect, useState } from 'react'
import { ObservableValue } from '../utils/ObservableValue'
import { GeneratedConnectionInterfaces } from './types'

export interface ConnectionInterfaceConfig {
  getConnectionInterfaces: (connectionType: string) => Promise<string[]>,
  isConnectionInterfaceNameAvailable: (name: string) => Promise<boolean>,
  onImportPlugin?: (event: React.SyntheticEvent<any>) => void,
}

const configContext = createContext<ConnectionInterfaceConfig | undefined>(undefined)

const generatedConnectionContext = createContext<ObservableValue<GeneratedConnectionInterfaces> | undefined>(undefined)

export const ConnectionInterfaceConfigProvider = configContext.Provider

export const GeneratedConnectionsProvider = generatedConnectionContext.Provider

export function useConnectionInterfaceConfig() {
  const value = useContext(configContext)
  if (!value) throw new Error('Can\'t use "useConnectionInterfaceConfig" without a "ConnectionInterfaceProvider" in the React tree.')
  return value
}

function useGeneratedConnectionsObservable() {
  const observable = useContext(generatedConnectionContext)
  if (!observable) throw new Error('Can\'t use generated connections without a "GlobalContext" in the React tree.')
  return observable
}

export function useGeneratedConnectionsManager() {
  const observable = useGeneratedConnectionsObservable()

  return {
    set(name: string, type: string, value: string) {
      observable.set({ ...observable.get(), [name]: { type, value } })
    },
    unset(name: string) {
      observable.set(omit(observable.get(), name))
    },
    getByType(type: string) {
      return Object.values(observable.get()).filter(i => i.type === type).map(i => i.value)
    },
    observable,
  }
}

export function useGeneratedConnections(type: string) {
  const { getByType, observable } = useGeneratedConnectionsManager()
  const [generated, setGenerated] = useState<string[]>(getByType(type))
  useEffect(() => observable.onChange(() => setGenerated(getByType(type))), [type])
  return generated
}

export type GeneratedConnectionsManager = ReturnType<typeof useGeneratedConnectionsManager>
