import { AxiosInstance } from "axios";
import { TextBoxFactory } from "../ComponentFactory/TextBoxFactory";
import { MainStateManager } from "../MainStateManager";
import { ElementsOfFormFactory } from "../Page/ElementsOfFormFactory";
import { Argument } from "../Page/ElementsOfFormFactory/Argument";
import { IMainStateFactory } from "../Types";
import {
    AccountColumn,
    DetailedAccountColumn,
    CustomerColumn,
    CostCenterColumn,
    BankColumn,
    BranchColumn,
    CarColumn,
    CashColumn,
    DriveColumn,
    PersonColumn,
    PurchaseOfficerColumn,
    SaleManagerColumn,
    StakeholderColumn,
    CapitalistColumn,
    VisitorColumn,
    StringColumn,
    CountColumn,
    QTYColumn,
    NumberOfCheckColumn,
    DateColumn,
    NumberColumn,
    AmountColumn,
    IdColumn,
    GridViewColumn,
    GridViewMergCaptionColumn,
    RowColumn,
    IconColumn,
    NumberIconColumn,
    LockUnLockColumn,
} from "./Columns";
import { PATH, SEARCH } from "amisa-paths";
import { useAxios } from "../AmisaAuth/Models/StorageManager/TokenInfo";

export type ISpinnerType = 'Main' | 'Form' | 'Table';

export type GridViewPATHS = PATH & {
    search: string;
    delete: string;
} & {
    unLock?: string;
    lock?: string;
};

export class GridViewFactory implements IMainStateFactory {
    public onAccept?: Function;
    public onCancel?: Function;

    public argument?: Argument;
    public getTextBoxFactory = (fieldName: string): TextBoxFactory => {
        const selfFactoryName = 'selfFactory' + fieldName;
        return this.any[selfFactoryName];
    }
    public cach: {} = {};
    public forceUpdate = () => { };
    public ContextMenuRow?: React.ComponentType<{ headFactory: GridViewFactory, row: any }>;
    public apiAxios: AxiosInstance;
    public columns: GridViewColumn[] = [];
    public columnsReverse: GridViewColumn[] = [];

    public mergeCaptionColumns: GridViewMergCaptionColumn[] | null = null;
    public rows: any[] = [];
    public waitForLoad?: boolean;
    public currentRowRef?: React.RefObject<HTMLTableRowElement>;
    public showWaitingSpinner: () => void;
    public closeWaitingSpinner: () => void;

    public get any(): any {
        return this;
    }
    public elementsOfForm: ElementsOfFormFactory;

    constructor(
        public mainStateManager: MainStateManager,
        public urls: GridViewPATHS,
        public spinnerType: ISpinnerType,
        public hasPagination?: boolean,
        initializeCustomPayLoad?: any,
    ) {
        this.elementsOfForm = new ElementsOfFormFactory(this, initializeCustomPayLoad);
        this.apiAxios = useAxios(this.urls);

        switch (this.spinnerType) {
            case 'Form':
                this.showWaitingSpinner = this.elementsOfForm.showWaitingFormSpinner;
                this.closeWaitingSpinner = this.elementsOfForm.closeWaitingFormSpinner;
                break;
            case 'Table':
                this.showWaitingSpinner = this.elementsOfForm.showWaitingTableSpinner;
                this.closeWaitingSpinner = this.elementsOfForm.closeWaitingTableSpinner;
                break;
            default:
                this.showWaitingSpinner = this.elementsOfForm.showFullScreenWaittingSpinner
                this.closeWaitingSpinner = this.elementsOfForm.closeFullScreenWaittingSpinner;
                break;
        }
    }

    public deleteRow = (caption: string, text: string, main: string) => {
        if (this.isValidCurrenRowId) {
            this.elementsOfForm.showAreYouSureDeleteMessageBox(this.deleteRowFinal, caption, text, main);
        } else {
            this.elementsOfForm.showInvalidArgumentMessageBox('هیچ ردیف فعالی به درستی انتخاب نشده است');
        }
    }

    private deleteRowFinal = () => {
        this.showWaitingSpinner();

        const yearId = this.currentRow.getProp('yearId');
        if (!(typeof yearId === 'number' && yearId > 0)) {
            this.elementsOfForm.closeWaitingFormSpinner();
            this.elementsOfForm.showInvalidArgumentMessageBox('شناسه سال مالی فعال معتبر نمیباشد');
            return;
        }

        this.apiAxios.post(this.urls.delete, { ...this.elementsOfForm.searchParameter, idForDelete: this.currentRow.getProp('id'), yearId: yearId })
            .then(response => {
                if (response.data.isSuccess) {
                    this.closeWaitingSpinner();
                    this.rows = response.data.rows;
                    this.elementsOfForm.pageParameter.totalPages = response.data.searchParameter.totalPages;
                    this.elementsOfForm.pageParameter.currentPage = response.data.searchParameter.currentPage;
                    this.forceUpdate();
                } else {
                    this.closeWaitingSpinner();
                    this.elementsOfForm.showInvalidArgumentMessageBox(response.data.messageRoot);
                }
            })
            .catch(e => {
                this.closeWaitingSpinner();
                this.elementsOfForm.showErrorMessageBox(e);
            });
    }

    loadData = () => {
        this.showWaitingSpinner();

        this.apiAxios.post(this.urls.search, this.elementsOfForm.searchParameter)
            .then(response => {
                if (response.data.isSuccess) {
                    this.closeWaitingSpinner();
                    this.rows = response.data.rows;

                    this.hideAutoHideColumns();

                    this.elementsOfForm.pageParameter.totalPages = response.data.searchParameter.totalPages;
                    this.elementsOfForm.pageParameter.currentPage = response.data.searchParameter.currentPage;
                    this.forceUpdate();
                } else {
                    this.closeWaitingSpinner();
                    this.rows = [];
                    this.elementsOfForm.showInvalidArgumentMessageBox(response.data.messageRoot);
                }
            })
            .catch(e => {
                this.closeWaitingSpinner();
                this.rows = [];
                this.elementsOfForm.showErrorMessageBox(e);
            });
    }

    private hideAutoHideColumns() {
        const autoHidColumns = this.columns.filter(i => i.autoHideIfEmpty);

        autoHidColumns.forEach(column => {
            column.visible = this.rows.some(row => !column.isCellValueEmpty(row));
        });
    }

    public selectThisRowById = (_rowId: number) => {
        throw new Error('Method not implemented.');
    }
    public selectThisRowByIndex = (rowIndex: number) => {
        return this.currentRowIndex === rowIndex;
    }
    public showContextMenuForRow = (_rowData: any, _rowIndex: number, _arg2: number, _arg3: number) => {
        throw new Error('Method not implemented.');
    }
    public hideContextMenuForRow = () => {
        throw new Error('Method not implemented.');
    }

    public get isValidCurrenRowId() {
        if (this.rows && this.rows.length > 0 && typeof this.currentRowIndex === 'number') {
            const currentRow = this.rows[this.currentRowIndex];
            const id = currentRow.getProp('id');

            return typeof id === 'number' && id > 0;
        }
        return false;
    }
    public get currentRow() {
        if (this.rows && this.rows.length > 0 && typeof this.currentRowIndex === 'number') {
            return this.rows[this.currentRowIndex];
        }
    }
    public get currentRowId(): number | undefined {
        return this.currentRow.getProp('id');
    }
    public get currentRowYearId(): number | undefined {
        return this.currentRow.getProp('yearId');
    }

    public currentRowIndex = 0;
    public isThisCurrentRow = (rowIndex: number) => {
        return this.currentRowIndex === rowIndex;
    }
    public selectedRowsIds: number[] = [];
    public isSelectedThisRow = (rowId: number) => {
        return this.selectedRowsIds.includes(rowId);
    }

    public selectThisCell = (rowIndex: any, _columnIndex: number): void => {
        this.currentRowIndex = rowIndex;
        this.elementsOfForm.toolStripFactory.forceUpdateToolStackMenu();
        this.forceUpdate();
    }
    public refreshList = () => {
        this.loadData();
    }

    public getWidth(child: any): number {
        const width = child.props.width;
        const level = child.props.level;
        if (typeof width === 'number') {
            return width;
        }
        const setting = (this.mainStateManager as any).Setting;

        if (child.type === AccountColumn) {
            if (level === 1) {
                return setting.structureAccountCoding.levelLen1 * 5;
            } else if (level === 2) {
                return setting.structureAccountCoding.untilLevelLen2 * 5;
            } else if (level === 3) {
                return setting.structureAccountCoding.untilLevelLen3 * 5;
            } else if (level === 4) {
                return setting.structureAccountCoding.untilLevelLen4 * 5;
            } else if (level === 5) {
                return setting.structureAccountCoding.untilLevelLen5 * 5;
            } else if (level === 6) {
                return setting.structureAccountCoding.untilLevelLen6 * 5;
            } else if (level === 7) {
                return setting.structureAccountCoding.untilLevelLen7 * 5;
            } else if (level === 8) {
                return setting.structureAccountCoding.untilLevelLen8 * 5;
            } else if (level === 9) {
                return setting.structureAccountCoding.untilLevelLen9 * 5;
            } else {
                return 100;
            }
        } else if (child.type === DetailedAccountColumn) {
        } else if (child.type === CustomerColumn) { } else if (child.type === CostCenterColumn) {
        } else if (child.type === BankColumn) {
        } else if (child.type === BranchColumn) {
        } else if (child.type === CarColumn) {
        } else if (child.type === CashColumn) {
        } else if (child.type === DriveColumn) {
        } else if (child.type === PersonColumn) {
        } else if (child.type === PurchaseOfficerColumn) {
        } else if (child.type === SaleManagerColumn) {
        } else if (child.type === StakeholderColumn) {
        } else if (child.type === CapitalistColumn) {
        } else if (child.type === VisitorColumn) {
        } else if (child.type === StringColumn) {
            return 120;
        } else if (child.type === CountColumn) {
            return 50;
        } else if (child.type === QTYColumn) {
            return 70;
        } else if (child.type === NumberOfCheckColumn) {
            return 90;
        } else if (child.type === DateColumn) {
            return 90;
        } else if (child.type === NumberColumn) {
            return 30;
        } else if (child.type === AmountColumn) {
            return 90;
        } else if (child.type === IdColumn) {
            return 30;
        } else if (child.type === RowColumn) {
            return 30;
        } else if (child.type === IconColumn) {
            return 20;
        } else if (child.type === NumberIconColumn) {
            return 20;
        } else if (child.type === LockUnLockColumn) {
            return 20;
        }
        return 100;
    }

    public close = () => {
        if (this.elementsOfForm.subPageItem) {
            this.elementsOfForm.subPageItem.close();
        } else if (this.elementsOfForm.currentModal) {
            this.elementsOfForm.currentModal.close();
        }
    }

    public nextRow = () => {
        if (this.currentRowIndex === this.rows.length - 1) {
            this.currentRowIndex = 0;
        } else {
            this.currentRowIndex += 1;
        }
        this.forceUpdate();

        setTimeout(() => {
            this.currentRowRef?.current?.scrollIntoView({
                behavior: 'auto',
                inline: 'center',
                block: 'center',
            })
        }, 90);
    }

    public previousRow = () => {
        if (this.currentRowIndex === 0) {
            this.currentRowIndex = this.rows.length - 1;
        } else {
            this.currentRowIndex -= 1;
        }
        this.forceUpdate();

        setTimeout(() => {
            this.currentRowRef?.current?.scrollIntoView({
                behavior: 'auto',
                inline: 'center',
                block: 'center',
            })
        }, 90);
    }

    public getLockOrginalValue = (row: any) => {
        return row['isLockOrginalValueTemp'];
    }

    private setCachValueOfLockState = (fieldName: string, newValue: boolean) => {
        const isLockOrginalValueTemp = (): boolean | undefined => {
            if (this.currentRow) {
                return this.getLockOrginalValue(this.currentRow);
            }
            return undefined;
        }
        const currentValue = this.currentRow.getProp(fieldName);
        const cachValueOfLockState = isLockOrginalValueTemp();
        if (cachValueOfLockState === undefined && newValue !== currentValue) {
            this.currentRow['isLockOrginalValueTemp'] = currentValue;
        } else {
            if (cachValueOfLockState === newValue) {
                delete this.currentRow['isLockOrginalValueTemp'];
            }
        }
        this.currentRow.setProp(fieldName, newValue);
    }

    public toggelLockUnlock = (fieldName: string) => {
        const currentValue = this.currentRow.getProp(fieldName);
        if (currentValue) {
            this.unLock(fieldName);
        } else {
            this.lock(fieldName);
        }

    }

    public lock = (fieldName: string) => {
        if (!this.urls.lock) {
            this.elementsOfForm.showInvalidArgumentMessageBox('امکان قفل کردن ردیف ها، موجود نمیباشد');
            return;
        }
        if (this.isValidCurrenRowId) {
            const yearId = this.currentRow.getProp('yearId');
            if (!(typeof yearId === 'number' && yearId > 0)) {
                this.elementsOfForm.closeWaitingFormSpinner();
                this.elementsOfForm.showInvalidArgumentMessageBox('شناسه سال مالی فعال معتبر نمیباشد');
                return;
            }


            this.lockUnLock(this.urls.lock, this.currentRowId!, yearId, () => {
                this.setCachValueOfLockState(fieldName, true);
            });
        } else {
            this.elementsOfForm.showInvalidArgumentMessageBox('هیچ ردیف فعالی به درستی انتخاب نشده است');
        }
    }

    public unLock = (fieldName: string) => {
        if (!this.urls.unLock) {
            this.elementsOfForm.showInvalidArgumentMessageBox('امکان باز کردن قفل ردیف ها، موجود نمیباشد');
            return;
        }
        if (this.isValidCurrenRowId) {
            const yearId = this.currentRow.getProp('yearId');
            if (!(typeof yearId === 'number' && yearId > 0)) {
                this.elementsOfForm.closeWaitingFormSpinner();
                this.elementsOfForm.showInvalidArgumentMessageBox('شناسه سال مالی فعال معتبر نمیباشد');
                return;
            }
            this.lockUnLock(this.urls.unLock, this.currentRowId!, yearId, () => {
                this.setCachValueOfLockState(fieldName, false);
            });
        } else {
            this.elementsOfForm.showInvalidArgumentMessageBox('هیچ ردیف فعالی به درستی انتخاب نشده است');
        }
    }


    public lockUnLock = (path: string, id: number, yearId: number, afterSuccessed: () => void) => {
        this.showWaitingSpinner();

        this.apiAxios.post(`${path}/${id}/${yearId}`, {}, this.mainStateManager.tokenInfo.headerOfAxios)
            .then(response => {
                if (response.data.isSuccess) {
                    afterSuccessed();
                    this.closeWaitingSpinner();
                    this.forceUpdate();
                } else {
                    this.closeWaitingSpinner();
                    this.elementsOfForm.showInvalidArgumentMessageBox(response.data.messageRoot);
                }
            })
            .catch(e => {
                this.closeWaitingSpinner();
                this.elementsOfForm.showErrorMessageBox(e);
            });
    }
}
