import {Model} from './Model';
import Dexie from 'dexie';

export interface IMenuItem {
    id?: number;
    serverId: string;
    name: string;
    childIds?: string[];
    noDelete?: boolean;
    noChildren?: boolean;
    virtual?: boolean;
    type?: string;
    shared?: boolean;
    needsServerUpdate?: boolean;
    offlineUpdatedAt?: string;
}

export class MenuItem extends Model<IMenuItem> implements IMenuItem {
    id?: number;
    serverId: string;
    name: string;
    childIds?: string[];
    noDelete?: boolean;
    noChildren?: boolean;
    virtual?: boolean;
    type?: string;
    shared?: boolean;
    needsServerUpdate?: boolean;
    offlineUpdatedAt?: string;

    public static getTableName() {
        return 'menuItems';
    }

    public static getSchema() {
        return '++id, serverId, name, childIds, noDelete, noChildren, virtual, type, shared, needsServerUpdate, offlineUpdatedAt';
    }

    public static deflateTree(nodes: any[]): MenuItem[] {
        let items = [];

        for ( const node of nodes ) {
            const childIds = node.children ? node.children.map(x => x.id) : [];
            const item = new MenuItem(node.name, node.id, childIds, node.noDelete, node.noChildren, node.virtual, node.type, node.shared);

            items.push(item);
            if ( node.children ) {
                items = items.concat(...this.deflateTree(node.children));
            }
        }

        return items;
    }

    public static inflateTree(items: MenuItem[]) {
        const serverIdXItems: { [key: string]: MenuItem[] } = {};

        for ( const item of items ) {
            if ( !serverIdXItems[item.serverId] ) {
                serverIdXItems[item.serverId] = [];
            }

            serverIdXItems[item.serverId].push(item);
        }

        const inflateNode = (item, alreadyChildren = [], seen = []) => {
            const node: any = item.getSaveRecord();
            seen.push(item);
            node.id = node.serverId;

            node.children = [];
            if ( item.childIds ) {
                for ( const childId of item.childIds ) {
                    if ( serverIdXItems[childId] ) {
                        const children = serverIdXItems[childId].filter(x => {
                            if ( x.type !== 'page' && item.serverId !== x.serverId ) {
                                return false;
                            }

                            return x !== item && !alreadyChildren.includes(x) && !seen.includes(x);
                        });

                        node.children = node.children.concat(...children.map(x => inflateNode(x, children, seen)));
                    }
                }
            }

            const pageChildren = [];
            const otherChildren = [];
            for ( const child of node.children ) {
                if ( child.type === 'page' ) {
                    pageChildren.push(child);
                } else {
                    otherChildren.push(child);
                }
            }

            node.children = [...otherChildren, ...pageChildren];
            return node;
        };

        const topLevelItems = items.filter(x => String(x.serverId) === '0');
        return topLevelItems.map(x => inflateNode(x));
    }

    constructor(
        name: string,
        serverId: string,
        childIds?: string[],
        noDelete?: boolean,
        noChildren?: boolean,
        virtual?: boolean,
        type?: string,
        shared?: boolean,
        needsServerUpdate?: boolean,
        offlineUpdatedAt?: string,
        id?: number
    ) {
        super();

        this.name = name;
        this.serverId = serverId;
        if ( childIds ) {
            this.childIds = childIds;
        }

        if ( typeof noDelete !== 'undefined' ) {
            this.noDelete = noDelete;
        }

        if ( typeof noChildren !== 'undefined' ) {
            this.noChildren = noChildren;
        }

        if ( typeof virtual !== 'undefined' ) {
            this.virtual = virtual;
        }

        if ( type ) {
            this.type = type;
        }

        if ( typeof shared !== 'undefined' ) {
            this.shared = shared;
        }

        if ( typeof needsServerUpdate !== 'undefined' ) {
            this.needsServerUpdate = needsServerUpdate;
        }

        if ( typeof offlineUpdatedAt !== 'undefined' ) {
            this.offlineUpdatedAt = offlineUpdatedAt;
        }

        if ( id ) {
            this.id = id;
        }
    }

    public getDatabase(): Dexie.Table<IMenuItem, number> {
        return this.staticClass().dbService.table('menuItems') as Dexie.Table<IMenuItem, number>;
    }

    public getSaveRecord(): any {
        return {
            ...(this.id ? { id: this.id } : {}),
            serverId: this.serverId,
            name: this.name,
            ...(typeof this.childIds !== 'undefined' ? { childIds: this.childIds } : {}),
            ...(typeof this.noDelete !== 'undefined' ? { noDelete: this.noDelete } : {}),
            ...(typeof this.noChildren !== 'undefined' ? { noChildren: this.noChildren } : {}),
            ...(typeof this.virtual !== 'undefined' ? { virtual: this.virtual } : {}),
            ...(typeof this.type !== 'undefined' ? { type: this.type } : {}),
            ...(typeof this.shared !== 'undefined' ? { shared: this.shared } : {}),
            ...(typeof this.needsServerUpdate !== 'undefined' ? { needsServerUpdate: this.needsServerUpdate } : {}),
            ...(typeof this.offlineUpdatedAt !== 'undefined' ? { offlineUpdatedAt: this.offlineUpdatedAt } : {}),
        };
    }
}
