import { once } from 'lodash';
import React, { createContext } from 'react';

type ErrorMap<T extends { [key: string]: any }> = { [key in keyof T]?: string };

export type FieldRegisterModel = {
  getError(): string | undefined;
  getValue(): any;
};
interface FormObjectContext<T extends Record<string, any>> {
  value: T;
  valueRef: React.MutableRefObject<T>;
  errors: ErrorMap<T>;
  register: (fieldName: string, field: FieldRegisterModel) => void;
  validate: (fieldName: string) => void;
  onChange: (name: string, change?: any, isValid?: boolean) => void;
}

const defaultContext: FormObjectContext<any> = {
  value: {},
  errors: {},
  valueRef: React.createRef(),
  register: () => {},
  validate: () => {},
  onChange: (name, change) => console.log('context got form change', name, change),
};

// Using once to get the generic to work
function _getFieldContext<T extends Record<string, any>>() {
  return createContext<FormObjectContext<T>>(defaultContext as any);
}

export const getFieldContext = once(_getFieldContext);

export function FormObjectProvider<T extends { [key: string]: any }>({
  children,
  ...rest
}: FormObjectContext<T> & { children: React.ReactNode }) {
  const { Provider } = getFieldContext<T>();
  return <Provider value={rest}>{children}</Provider>;
}
