import { ITypeOfFormForRoute } from "../../AmisaAuth/Menus/1-MenuFactory";
import { AttachedFilesFactory } from "../../ComponentFactory/AttachedFilesFactory";
import { ModalFactory } from "../../ComponentFactory/ModalFactory";
import { IPopupMouseLocation, PopupFactory } from "../../ComponentFactory/PopupFactory";
import { ToolStripFactory } from "../../ComponentFactory/ToolStrip/ToolStripFactory";
import { MainStateManager } from "../../MainStateManager";
import { IMainStateFactory, OfficialAttacheFormsType } from "../../Types";
import { Argument } from "./Argument";
import { ElementFactory } from "./ElementFactory";
import { SubPageItem } from "./SubPageItem";
import { SubPagesFactory } from "./SubPagesFactory";
import { Tabbing } from "./Tabbing";
import { IFocusAbleElementFactory } from "./Tabbing/ElementTabbing";


export type IParentFormManager = MainStateManager | SubPageItem;
interface IPageParameter {
    totalPages: number | null;
    itemsPerPage: number,
    currentPage: number
};

export class ElementsOfFormFactory {
    public subPageItem?: SubPageItem;
    public filters: any = {};
    public isShowWaitingFormSpinner?: boolean;
    public isShowWaitingTableSpinner?: boolean;
    public tabbing: Tabbing;
    public customPayLoad: any;

    public initializeElements = () => {
        this.elements.forEach(element => {
            element.clearData();
        });
    }

    public get headPayLoad() {
        const convertOtherToObject = () => {
            const initialValue = {};
            return this.otherPayLoad?.reduce((obj: any, item) => {
                return {
                    ...obj,
                    [item.payLoadKey!]: item.object.getProp(item.fieldName),
                };
            }, initialValue);
        };

        const other = convertOtherToObject();

        const convertPayloadToObject = () => {
            const initialValue = {};
            return this.payLoad?.reduce((obj: any, item: ElementFactory) => {
                return {
                    ...obj,
                    [item.payLoadKey!]: item.value,
                };
            }, initialValue);
        };

        const payload = convertPayloadToObject();

        return { ...other, ...payload, ...this.customPayLoad };
    }


    public get searchParameter() {
        return { ...this.filters, ...this.pageParameter, ...this.headPayLoad };
    }

    public responses?: ElementFactory[];
    public addResponseElement = (element: ElementFactory) => {
        if (this.responses === undefined) {
            this.responses = [];
        }

        this.responses.push(element);
    }
    public deserializedResponse = (data: any) => {
        if (this.responses &&
            this.responses.length > 0) {
            this.responses.forEach((element: ElementFactory) => {
                element.deseriallize(data.getProp(element.responseKey!));
            });
        }
    }

    public otherPayLoad: { object: any, payLoadKey: string, fieldName: string }[] = [];
    public addOtherPayLoadKey = (object: any, payLoadKey: string, fieldName: string) => {
        if (typeof payLoadKey === 'string' && !this.otherPayLoad.find(i => i.payLoadKey === payLoadKey)) {
            this.otherPayLoad.push({ object, payLoadKey, fieldName });
        }
    }

    public payLoad?: ElementFactory[];
    public addPayloadElement = (element: ElementFactory) => {
        if (this.payLoad === undefined) {
            this.payLoad = [];
        }

        this.payLoad.push(element);
    }

    public pageParameter: IPageParameter;
    public gotoPage = (page: number) => {
        if (typeof page === 'number' && page > 0 && typeof this.pageParameter.totalPages === 'number' && page <= this.pageParameter.totalPages) {
            this.pageParameter.currentPage = page;
        } else {
            this.pageParameter.currentPage = 1;
        }
    }
    public goNextPage = () => {
        if (typeof this.pageParameter.totalPages === 'number' && this.pageParameter.currentPage < this.pageParameter.totalPages) {
            this.pageParameter.currentPage = this.pageParameter.currentPage + 1;
        }
    }
    public goPreviousPage = () => {
        if (this.pageParameter.currentPage > 1) {
            this.pageParameter.currentPage = this.pageParameter.currentPage - 1;
        }
    }
    public goLastPage = () => {
        if (typeof this.pageParameter.totalPages === 'number') {
            this.pageParameter.currentPage = this.pageParameter.totalPages
        }
    }
    public goFirstPage = () => {

    }
    public mainStateManager: MainStateManager;

    public showSendByLetterForm = (type: OfficialAttacheFormsType, object: { id: number }) => {
        if (!object) {
            this.showInvalidArgumentMessageBox('اطلاعاتی به درستی برای ارسال نامه تشخیص داده نشد');
            console.error('invalid  object to add letter', object);
            return;
        }

        const id = object.getProp('id');
        if (!(typeof id === 'number' && id > 0)) {
            this.showInvalidArgumentMessageBox('شناسه به درستی تشخیص داده نشده');
            console.error('invalid field id in object to add letter', object);
            return;
        }
        switch (type) {
            case OfficialAttacheFormsType.AnbarHead:
            case OfficialAttacheFormsType.OfficialAppointment:
            case OfficialAttacheFormsType.OfficialCall:
            case OfficialAttacheFormsType.OfficialEmail:
            case OfficialAttacheFormsType.OfficialLetter:
            case OfficialAttacheFormsType.OfficialNote:
            case OfficialAttacheFormsType.OfficialSms:
            case OfficialAttacheFormsType.OfficialTask:
                break;
            default:
                const yearId = object.getProp('yearId');
                if (!(typeof yearId === 'number' && yearId > 0)) {
                    this.showInvalidArgumentMessageBox('سال مالی به درستی تشخیص داده نشده');
                    console.error('invalid field yearid in object to add letter', object);
                    return;
                }
                break;
        }

        this.mainStateManager.showSendByLetterForm(type, object);
    }
    public closeSendByLetterForm = () => {
        this.mainStateFactory.mainStateManager.sendByLetterForm?.close();
    }

    public popup?: PopupFactory;
    public showPopup = (children: JSX.Element, element?: IPopupMouseLocation, onClosedPopup?: () => void) => {
        if (this.mainStateFactory.elementsOfForm.popup) {
            return;
        }
        this.mainStateManager.showPopup(this.mainStateFactory, children, element, onClosedPopup);
    }
    public closePopup = () => {
        this.popup?.close();
    }

    public currentModal?: ModalFactory;

    public childModal?: ModalFactory;
    public showModal = (
        children: JSX.Element,
        onClosedModal?: () => void,
        argument?: number | string | object,
        customPayload?: object,
        finedInRows?: boolean,
        ExtraStackMenuComponent?: React.ComponentType<{ mainState: any }>,
        typeOfForm?: ITypeOfFormForRoute,
        cssClasses?: string,
    ) => {

        if (this.mainStateFactory.elementsOfForm.childModal) {
            return;
        }
        let argumentClass: Argument | undefined;
        if (typeof argument === 'number') {
            argumentClass = Argument.Id(argument, finedInRows);
        } else if (typeof argument === 'string') {
            argumentClass = Argument.Code(argument, finedInRows);
        } else if (typeof argument === 'object') {
            argumentClass = Argument.Object(argument, finedInRows);
        } else {
            argumentClass = Argument.Object({}, false);
        }

        argumentClass.typeOfForm = typeOfForm;
        argumentClass.ExtraStackMenuComponent = ExtraStackMenuComponent;
        argumentClass.customPayload = customPayload;

        this.mainStateManager.showModal(this.mainStateFactory, children, false, onClosedModal, argumentClass, cssClasses);
    }
    public closeModal = () => {
        this.childModal?.close();
    }
    public onCloseModalGetFocus?: () => void;
    public onCloseModalOpenNexWindow?: () => void;

    public showFullScreenWaittingSpinner = (onClosedModal?: () => void) => {
        this.mainStateManager.showFullScreenWaittingSpinner(this.mainStateFactory, onClosedModal);
    }
    public closeFullScreenWaittingSpinner = () => {
        this.childModal?.close();
    }

    public showSomeThingWentWrong = (onClosedModal?: () => void) => {
        this.mainStateManager.showSomeThingWentWrong(this.mainStateFactory, onClosedModal);
    }
    public showErrorMessageBox = (error: Error, onClosedModal?: () => void) => {
        this.mainStateManager.showErrorMessageBox(this.mainStateFactory, error, onClosedModal);
    }
    public showInvalidArgumentMessageBox = (description: string, onClosedModal?: () => void) => {
        this.mainStateManager.showInvalidArgumentMessageBox(this.mainStateFactory, description, onClosedModal);
    }
    public showSuccessFullMessageBox = (caption?: string, text?: string, description?: string, onClosedModal?: () => void) => {
        this.mainStateManager.showSuccessFullMessageBox(this.mainStateFactory, caption, text, description, onClosedModal);
    }
    public showAreYouSureDeleteMessageBox = (onClickDelete: () => void, caption?: string, text?: string, description?: string) => {
        this.mainStateManager.showAreYouSureDeleteMessageBox(this.mainStateFactory, onClickDelete, caption, text, description);
    }
    public showThereAreSomeErrorYouCanNot = (countOfError: number, onClosedModal?: () => void) => {
        this.mainStateManager.showThereAreSomeErrorYouCanNot(this.mainStateFactory, countOfError, onClosedModal);
    }
    public showThereIsNotAnyChangeForSave = (onClosedModal?: () => void) => {
        this.mainStateManager.showThereIsNotAnyChangeForSave(this.mainStateFactory, onClosedModal);
    }
    public showAttachedFiles = (
        argument: string | number | object | undefined,
        axiosData: {
            controllerPath: string;
            acceptPath?: string;
            getListPath?: string;
            getByIdPath?: string;
            deletePath?: string;
        },
        caption?: string,
        onClosedModal?: (() => void),

    ) => {
        this.mainStateManager.showAttachedFiles(this.mainStateFactory, argument, axiosData, caption, onClosedModal);
    }
    public showWaitingFormSpinner = () => {
        this.isShowWaitingFormSpinner = true;
        const forceUpdate = this.mainStateFactory.any.forceUpdate;
        if (typeof forceUpdate === 'function') {
            forceUpdate();
        }
    }
    public closeWaitingFormSpinner = () => {
        this.isShowWaitingFormSpinner = false;
        const forceUpdate = this.mainStateFactory.any.forceUpdate;
        if (typeof forceUpdate === 'function') {
            forceUpdate();
        }
    }

    public showWaitingTableSpinner = () => {
        this.isShowWaitingTableSpinner = true;
        const forceUpdate = this.mainStateFactory.any.forceUpdate;
        if (typeof forceUpdate === 'function') {
            forceUpdate();
        }
    }
    public closeWaitingTableSpinner = () => {
        this.isShowWaitingTableSpinner = false;
        const forceUpdate = this.mainStateFactory.any.forceUpdate;
        if (typeof forceUpdate === 'function') {
            forceUpdate();
        }
    }

    public get hasChange() {
        return this.elements.some(i => i.hasChange);
    }


    //** return number of error */
    public validate = (): number => {
        let numberofError = 0;

        this.elements.forEach(element => {
            element.validate();
            if (!(typeof element.validation === 'boolean' && element.validation === true)) {
                numberofError += 1;
            }
        });

        if (this.mainStateFactory.any.forceUpdate) {
            this.mainStateFactory.any.forceUpdate();
        }

        return numberofError;
    }

    public elements: ElementFactory[];
    public toolStripFactory: ToolStripFactory;
    public subPageFactory?: SubPagesFactory;
    public parentPageFactory?: SubPagesFactory;

    constructor(
        public mainStateFactory: IMainStateFactory,
        initializeCustomPayLoad?: any,
    ) {
        this.mainStateManager = this.mainStateFactory.mainStateManager;
        this.toolStripFactory = new ToolStripFactory(this);
        this.tabbing = new Tabbing(this);
        this.elements = [];
        this.pageParameter = {
            currentPage: 1,
            itemsPerPage: 50,
            totalPages: 1,
        }
        this.customPayLoad = initializeCustomPayLoad ? initializeCustomPayLoad : {};
    }

    addElement = (element: ElementFactory) => {
        this.elements.push(element)

        if (typeof element.tabIndex === 'number') {
            this.tabbing.elementTabbing.focusAbleElements.push(element as IFocusAbleElementFactory);
            this.tabbing.elementTabbing.focusAbleElements.sort((a, b) => a.tabIndex - b.tabIndex);
        }
    }

    removeElement = (element: ElementFactory) => {
        delete element.mainStateFactory.any[element.factoryFieldName];
        this.elements = this.elements.filter(i => i !== element);

        if (typeof element.tabIndex === 'number') {
            this.tabbing.elementTabbing.focusAbleElements = this.tabbing.elementTabbing.focusAbleElements.filter(i => i !== element);
            this.tabbing.elementTabbing.focusAbleElements.sort((a, b) => a.tabIndex - b.tabIndex);
        }
    }


    public focuseToThisElement = (factory: ElementFactory) => {
        if (typeof factory.tabIndex === 'number' && factory.element) {
            this.tabbing.elementTabbing.focusToElementByHTMLElement(factory.element);
        }
    }

    public saveAttachedFiles = async (id: number) => {
        const find = this.elements.find(i => i instanceof AttachedFilesFactory) as AttachedFilesFactory;
        if (find) {
            await find.save(id);
        }
    }


    public close = () => {
        if (this.subPageItem) {
            this.subPageItem.close();
        } else if (this.childModal) {
            this.childModal.mainStateFactory.any.dispose && this.childModal.mainStateFactory.any.dispose();
            this.childModal.close();
        } else if (this.subPageFactory && this.subPageFactory.subPages.length === 0) {
            this.mainStateFactory.any.dispose && this.mainStateFactory.any.dispose();
            this.mainStateManager.history && this.mainStateManager.history.push('/home');
        }
    }

}