import { registerStore } from '@wordpress/data';
import produce from 'immer';
import type {
	FilterProperties,
	FilterPropertyValues,
} from '../components/controls-inspector/sidebar/FiltersControl/FiltersControl';
import { adminAjaxFetch } from '../helpers';

export type Forms = { id: string; title: string }[];

export interface GFRestAPIForm {
	id: string;
	title: string;
}

export interface GFMergeTag {
	tag: string;
	label: string;
}

export interface FormMergeTags {
	[ group: string ]: { label: string | false; tags: GFMergeTag[] };
}

export interface GPEBState {
	forms: GFRestAPIForm[];
	formFields: { [ formId: string ]: any[] };
	formMeta: { [ formId: string ]: any[] };
	formMergeTags: { [ formId: string ]: FormMergeTags };
	entryProperties: { [ formId: string ]: FilterProperties };
	entryPropertyValues: {
		[ formId: string ]: { [ propertyId: string ]: FilterPropertyValues };
	};
}

const DEFAULT_STATE: GPEBState = {
	forms: [],
	formFields: {},
	formMeta: {},
	formMergeTags: {},
	entryProperties: {},
	entryPropertyValues: {},
};

const actions = {
	fetchForms() {
		return {
			type: 'FETCH_FORMS',
		};
	},

	setForms( forms ) {
		return {
			type: 'SET_FORMS',
			forms,
		};
	},

	fetchFormFields( formId ) {
		return {
			type: 'FETCH_FORM_FIELDS',
			formId,
		};
	},

	setFormFields( formId, formFields ) {
		return {
			type: 'SET_FORM_FIELDS',
			formId,
			formFields,
		};
	},

	fetchFormMeta( formId ) {
		return {
			type: 'FETCH_FORM_META',
			formId,
		};
	},

	setFormMeta( formId, formMeta ) {
		return {
			type: 'SET_FORM_META',
			formId,
			formMeta,
		};
	},

	fetchFormMergeTags( formId ) {
		return {
			type: 'FETCH_FORM_MERGE_TAGS',
			formId,
		};
	},

	setFormMergeTags( formId, formMergeTags ) {
		return {
			type: 'SET_FORM_MERGE_TAGS',
			formId,
			formMergeTags,
		};
	},

	fetchEntryProperties( formId ) {
		return {
			type: 'FETCH_ENTRY_PROPERTIES',
			formId,
		};
	},

	setEntryProperties( formId, entryProperties ) {
		return {
			type: 'SET_ENTRY_PROPERTIES',
			formId,
			entryProperties,
		};
	},

	fetchEntryPropertyValues( formId, propertyId ) {
		return {
			type: 'FETCH_ENTRY_PROPERTY_VALUES',
			formId,
			propertyId,
		};
	},

	setEntryPropertyValues( formId, propertyId, entryPropertyValues ) {
		return {
			type: 'SET_ENTRY_PROPERTY_VALUES',
			formId,
			propertyId,
			entryPropertyValues,
		};
	},
};

registerStore( 'gp-entry-blocks', {
	reducer( state: GPEBState = DEFAULT_STATE, action ) {
		switch ( action.type ) {
			case 'SET_FORMS':
				return {
					...state,
					forms: action.forms,
				};

			case 'SET_FORM_FIELDS':
				return produce( state, ( draft ) => {
					draft.formFields[ action.formId ] =
						action.formFields.fields;
				} );

			case 'SET_FORM_META':
				return produce( state, ( draft ) => {
					draft.formMeta[ action.formId ] =
						action.formMeta;
				} );

			case 'SET_FORM_MERGE_TAGS':
				return produce( state, ( draft ) => {
					draft.formMergeTags[ action.formId ] = action.formMergeTags;
				} );

			case 'SET_ENTRY_PROPERTIES':
				return produce( state, ( draft ) => {
					draft.entryProperties[ action.formId ] =
						action.entryProperties;
				} );

			case 'SET_ENTRY_PROPERTY_VALUES':
				return produce( state, ( draft ) => {
					if ( ! draft.entryPropertyValues[ action.formId ] ) {
						draft.entryPropertyValues[ action.formId ] = {};
					}

					draft.entryPropertyValues[ action.formId ][
						action.propertyId
					] = action.entryPropertyValues;
				} );
		}

		return state;
	},

	actions,

	selectors: {
		getForms( state: GPEBState ) {
			return state.forms;
		},

		getFormFields( state: GPEBState, formId ) {
			return state.formFields[ formId ] ?? [];
		},

		getFormMeta( state: GPEBState, formId ) {
			return state.formMeta[ formId ] ?? [];
		},

		getFormMergeTags( state: GPEBState, formId ) {
			return state.formMergeTags[ formId ] ?? [];
		},

		getEntryProperties( state: GPEBState, formId ) {
			return state.entryProperties[ formId ] ?? [];
		},

		getEntryPropertyValues( state: GPEBState, formId, property ) {
			return state.entryPropertyValues?.[ formId ]?.[ property ];
		},
	},

	controls: {
		FETCH_FORMS() {
			return adminAjaxFetch( {
				action: 'gpeb_get_forms',
			} );
		},

		FETCH_FORM_FIELDS( action ) {
			return adminAjaxFetch( {
				action: 'gpeb_get_form',
				formId: action.formId,
			} );
		},

		FETCH_FORM_META( action ) {
			return adminAjaxFetch( {
				action: 'gpeb_get_form_meta',
				formId: action.formId,
			} );
		},

		FETCH_FORM_MERGE_TAGS( action ) {
			return adminAjaxFetch( {
				action: 'gpeb_get_form_merge_tags',
				formId: action.formId,
			} );
		},

		FETCH_ENTRY_PROPERTIES( action ) {
			return adminAjaxFetch( {
				action: 'gpeb_get_entry_properties',
				formId: action.formId,
			} );
		},

		FETCH_ENTRY_PROPERTY_VALUES( action ) {
			return adminAjaxFetch( {
				action: 'gpeb_get_entry_property_values',
				formId: action.formId,
				propertyId: action.propertyId,
			} );
		},
	},

	resolvers: {
		*getForms() {
			const forms = yield actions.fetchForms();
			return actions.setForms( forms );
		},

		*getFormFields( formId ) {
			const formFields = yield actions.fetchFormFields( formId );
			return actions.setFormFields( formId, formFields );
		},

		*getFormMeta( formId ) {
			const formFields = yield actions.fetchFormMeta( formId );
			return actions.setFormMeta( formId, formFields );
		},

		*getFormMergeTags( formId ) {
			const formMergeTags = yield actions.fetchFormMergeTags( formId );
			return actions.setFormMergeTags( formId, formMergeTags );
		},

		*getEntryProperties( formId ) {
			const entryProperties = yield actions.fetchEntryProperties(
				formId
			);

			return actions.setEntryProperties( formId, entryProperties );
		},

		*getEntryPropertyValues( formId, propertyId ) {
			const entryPropertyValues = yield actions.fetchEntryPropertyValues(
				formId,
				propertyId
			);

			return actions.setEntryPropertyValues(
				formId,
				propertyId,
				entryPropertyValues
			);
		},
	},
} );
