import { App } from "../app"
import { WidgetSearcher } from "./widgetSearcher"
import { browserHashService } from "../service/browserHashService"
declare const TestR: WidgetTree
export class ComposerEntryPage extends R.ComposerEntryPage {
    constructor(path?: string) {
        super()
        this.widgetSearcher = new WidgetSearcher()
        if (path) {
            this.currentPath = path
        }
        this.widgetSearcher.events.listenBy(this, "widget", (Widget) => {
            this.preview(Widget)
            browserHashService.set("path", Widget)
        })
        App.testResourceMaintainer.events.listenBy(this, "reloaded", () => {
            this.setupCommonWidgets()
            if (this.currentPath) this.preview(this.currentPath)
        })
    }
    setupCommonWidgets() {
        Leaf.Widget.namespace.clear()
        if (TestR["Widget"]) {
            let CommonWidget: WidgetTree = TestR["Widget"]
            this.recursiveInclude(CommonWidget)
        }

    }
    recursiveInclude(ws: WidgetTree) {
        if (!ws) return
        for (let name in ws) {
            let Cons = ws[name]
            if (Cons.prototype instanceof Leaf.Widget) {
                Leaf.Widget.namespace.include(Cons)
                console.log("incluc", Cons)
            } else {
                this.recursiveInclude(Cons)
            }
        }

    }
    public currentPath: string
    preview(path: string) {
        this.currentPath = path
        let builder = new FakeWidgetBuilder(path)
        this.widgetPreview = builder.widget
    }
}


interface AnyWidgetConstructor {
    new (): Leaf.WidgetAny
}
interface WidgetInfo {
    name: string
    path: string
}
interface ListInfo {
    name: string
    reference: string
    type: string
}
type WidgetTree = {
    widgets: string[]
    [index: string]: WidgetTree | Leaf.WidgetAny | any
}
class FakeWidgetBuilder {
    maxRecursive = 3
    widget: Leaf.WidgetAny
    public Cons: AnyWidgetConstructor
    constructor(public readonly path: string, public readonly testData = null, private stack: string[] = []) {
        let Cons = this.Cons = this.resolve(path)
        let datas = Cons["TestDatas"] || []
        let test = testData || datas[0] && (datas[0] as any).json
        this.stack.push(path)
        this.BindedWidgets = Cons["BindedWidgets"] || []
        this.BindedLists = Cons["BindedLists"] || []
        this.widget = this.createWidget(Cons, test)
    }
    getWidget() {
        return this.widget
    }
    public BindedWidgets: WidgetInfo[] = []
    public BindedLists: ListInfo[] = []
    public getRecursiveDepth() {
        return this.stack.filter(item => item === this.path).length
    }
    private createWidget(Cons: AnyWidgetConstructor, data: any = {}) {
        console.error(this.getRecursiveDepth())
        let widget = new Cons() as Leaf.WidgetAny
        for (let widgetInfo of this.BindedWidgets) {
            let test = data[widgetInfo.name] || null
            if (!widgetInfo.path) continue
            if (this.getRecursiveDepth() > this.maxRecursive) break
            let builder = new FakeWidgetBuilder(widgetInfo.path, test, this.stack.slice())
            widget[widgetInfo.name] = builder.widget
        }
        for (let listInfo of this.BindedLists) {
            let tests = data[listInfo.name] || []
            if (!(tests instanceof Array)) {
                tests = [tests]
            }
            if (tests.length === 0) {
                // tree default list item
                tests = [null, null, null]
            }
            let ref = this.resolveListReference(listInfo)
            if (!ref) continue
            if (this.getRecursiveDepth() > this.maxRecursive) break
            for (let test of tests) {
                let builder = new FakeWidgetBuilder(ref, test, this.stack.slice())
                widget[listInfo.name]["push"](builder.widget)
            }
        }
        for (let name in data) {
            if (widget._VMFields.indexOf(name) >= 0) {
                widget.VM[name] = data[name]
            }
        }
        return widget
    }
    hasList(name: string, lists: ListInfo[] = this.BindedLists): boolean {
        for (let list of lists) {
            if (list.name === name) return true
        }
        return false
    }
    hasWidget(name: string, widgets: WidgetInfo[] = this.BindedWidgets): boolean {
        for (let widget of widgets) {
            if (name === widget.name) return true
        }
        return false
    }
    getWidgetByName(name: string, widgets: WidgetInfo[] = this.BindedWidgets): WidgetInfo {
        for (let widget of widgets) {
            if (widget.name === name) return widget
        }
        return null
    }
    getListByName(name: string, lists: ListInfo[] = this.BindedLists): ListInfo {
        for (let list of lists) {
            if (list.name === name) return list
        }
        return null
    }
    private resolve(path: string): AnyWidgetConstructor {
        let routes = path.split("/").filter(item => !!item).map(item => Leaf.Util.capitalize(item))
        let cur: WidgetTree = TestR
        let name: string
        while (name = routes.shift()) {
            cur = cur[name]
        }
        return cur as any as AnyWidgetConstructor
    }
    private resolveListReference(list: ListInfo) {
        if (list.type == "reference") {
            return list.reference
        } else if (list.type == "inline") {
            return list.reference
        } else {
            return null
        }
    }
}
