import { useMemo } from 'react'
import { JinjaContext, useJinjaContext } from '../context/JinjaContext'
import { JinjaContextVariableConfig } from '../context/JinjaContextValue'
import { JinjaVariable } from '../context/JinjaVariable'
import { ObservableValue } from '../utils/ObservableValue'
import { GeneratedConnectionsProvider } from './ConnectionInterface'
import { GeneratedConnectionInterfaces } from './types'

export interface UserVariableConfig {
  name: string,
  description?: string,
  value: any,
}

export type VarSource = 'plugin' | 'stack' | 'account' | 'auth' | 'workspace'

export interface VarMetadata {
  source: VarSource,
  description?: string,
}

interface Props {
  auth?: UserVariableConfig[],
  account?: UserVariableConfig[],
  workspace?: UserVariableConfig[],
  stack?: UserVariableConfig[],
  children: React.ReactNode,
}

const variablesContextName = 'dynamic-form-variables'
const pluginVariablesContextName = 'dynamic-form-plugin-variables'
export const globalVariablesContextName = 'dynamic-form-global-variables'

export function varListToVarObject(vars: UserVariableConfig[] | undefined, source: VarSource) {
  return vars?.reduce<Record<string, JinjaContextVariableConfig<VarMetadata>>>((result, variable) => ({
    ...result,
    [variable.name]: {
      initialValue: variable.value,
      metadata: {
        source,
        description: variable.description,
      },
    },
  }), {})
}

export const VariablesContext = ({ auth, account, workspace, stack, children }: Props) => {
  const accountVars = useMemo(() => varListToVarObject(account, 'account'), [account])
  const authVars = useMemo(() => varListToVarObject(auth, 'auth'), [auth])
  const workspaceVars = useMemo(() => varListToVarObject(workspace, 'workspace'), [workspace])
  const stackVars = useMemo(() => varListToVarObject(stack, 'stack'), [stack])
  const all = useMemo(() => ({ ...authVars, ...accountVars, ...workspaceVars, ...stackVars }), [account, auth, workspace, stack])
  return <JinjaContext name={variablesContextName} variables={all} prefix="var">{children}</JinjaContext>
}

export const PluginVariablesContext = ({ variables, children }: { variables: UserVariableConfig[], children: React.ReactNode }) => {
  const pluginVars = useMemo(() => varListToVarObject(variables, 'plugin') ?? {}, [variables])
  return <JinjaContext name={pluginVariablesContextName} variables={pluginVars} prefix="var">{children}</JinjaContext>
}

export const GlobalContext = ({ children }: { children: React.ReactNode }) => {
  const generatedConnections = useMemo(() => new ObservableValue<GeneratedConnectionInterfaces>({}), [])
  return (
    <GeneratedConnectionsProvider value={generatedConnections}>
      <JinjaContext name={globalVariablesContextName} variables={{}}>{children}</JinjaContext>
    </GeneratedConnectionsProvider>
  )
}

export function useContextVariables(): Record<string, JinjaVariable<VarMetadata>> {
  const variablesCtx = useJinjaContext(variablesContextName)
  const pluginVariablesCtx = useJinjaContext(pluginVariablesContextName)
  if (!variablesCtx) throw new Error('Dynamic form error: VariablesContext is not defined.')
  if (!pluginVariablesCtx) throw new Error('Dynamic form error: PluginVariablesContext is not defined.')
  return { ...variablesCtx.variables, ...pluginVariablesCtx.variables }
}
