import { Dispatch } from 'redux'
import { AbstractFormField } from '../interfaces'
import {
    SET_FORM_FIELD,
    SET_ASYNC_FORM_FIELD,
    RESET_FORM,
    DESTROY_FORM,
    SUBMIT_FORM_VALID,
    SUBMIT_FORM_INVALID,
} from '../constants'

/**
 * Update an individual field in the state
 */
export interface SetFormFieldAction {
    type: '@@cosmo-ui/SET_FORM_FIELD',
    name: string
    formName: string,
    field: AbstractFormField<any>
}

export interface SetAsyncFormFieldAction<T> {
    type: '@@cosmo-ui/SET_ASYNC_FORM_FIELD'
    name: string
    formName: string,
    value: T
}

export interface ResetFormAction {
    type: '@@cosmo-ui/RESET_FORM'
    formName: string
}

export interface DestroyFormAction {
    type: '@@cosmo-ui/DESTROY_FORM'
    formName: string
}

export interface SubmitFormValidAction {
    type: '@@cosmo-ui/SUBMIT_FORM_VALID'
    formName: string
    data?: any
    args?: any
}

export interface SubmitFormInvalidAction {
    type: '@@cosmo-ui/SUBMIT_FORM_INVALID'
    formName: string
    data?: any
    args?: any
}

export type FormAction = SetFormFieldAction
    | ResetFormAction
    | DestroyFormAction
    | SubmitFormValidAction
    | SubmitFormInvalidAction

export const resetForm = (formName: string): ResetFormAction =>
    ({ type: RESET_FORM, formName })

export const destroyForm = (formName: string): DestroyFormAction =>
    ({ type: DESTROY_FORM, formName })

/**
 * Regith now there is abolutely no difference between submitFormValid
 * and submitFormInvalid. All they do is mark the form as submitted
 * However they may carry additional responsibility in the future
 * so i have created 2 separate actions
 *
 * @param formName
 * @param data
 * @param args
 */
export const submitFormValid = (formName: string, data?: any, args?: any) =>
    ({ type: SUBMIT_FORM_VALID, formName, data, args })

export const submitFormInvalid = (formName: string, data?: any, args?: any) =>
    ({ type: SUBMIT_FORM_INVALID, formName, data, args })

export const setFormField =
    (name: string,
     formName: string,
     field: AbstractFormField<any>): SetFormFieldAction => ({
        type: SET_FORM_FIELD,
        name,
        formName,
        field,
        })

export const setAsyncFormField =
    (name: string,
     formName: string,
     value: any): SetAsyncFormFieldAction<any> => ({
        type: SET_ASYNC_FORM_FIELD,
        name,
        formName,
        value,
    })
