import * as PIXI from 'pixi.js'
import { extend, styleHandler, parse, getValue } from './utils'
import Component from './core'

let singleton: Component = new Component({
    uiDesignWidth: window.innerWidth,
})

export const configComponents = (config: Component.config) => {
    if (config) {
        singleton = new Component(config)
    }
}

export const AnimatedSprite = (animatedFrames: PIXI.Texture[], style: Layout.style = {}) => {
    return singleton.createElement('AnimatedSprite', extend(style, {
        animatedFrames,
    }))
}

export const Sprite = (image: Component.spriteImage, style: Layout.style = {}) => {
    return singleton.createElement('Sprite', extend(style, {
        backgroundImage: image,
    }))
}

export const Container = (style: Layout.style = {}) => {
    return singleton.createElement('Container', style)
}

export const Rect = (style: Layout.style = {}) => {
    return singleton.createElement('Rect', style)
}

export const Text = (content: string, style: Layout.style = {}) => {
    return singleton.createElement('Text', extend(style, {
        content,
    }))
}

export const Circle = (style: Layout.style = {}) => {
    return singleton.createElement('Circle', style)
}

const styles = {}

export const style = (className: string | object, styleStr?: string) => {
    if (typeof className === 'string') {
        styles[className] = styleStr
    } else if (typeof className === 'object') {
        Object.keys(className).map((cls: string) => {
            styles[cls] = className[cls]
        })
    }
}

const createNode = (node: any, extra?: any) => {
    let element: any = null
    if (node.type === 'tag') {
        const { dataify, camelizify, parse, replaceValue } = styleHandler
        const { style = {}, src, className } = node.attrs
        const classStyle = parse(styles[className])
        const inlineStyle = parse(style)
        
        const _style = dataify(camelizify(extend(classStyle, inlineStyle)), extra)
        
        const image = replaceValue(src, extra)
        switch (node.name.toLowerCase()) {
            case 'sprite':
                element = Sprite(image, _style)
                break
            case 'animatedsprite':
                    element = AnimatedSprite(image, _style)
                    break
            case 'text':
                let content = ''
                node.children.map((child) => {
                    if (child.type === 'text') {
                        content += child.content
                    }
                })
                element = Text(content, _style)
                break
            case 'container':
                element = Container(_style)
                break
            case 'rect':
                element = Rect(_style)
                break
            case 'circle': 
                element = Circle(_style)
                break
        }
        Object.assign(element, node.attrs)
    } else if (node.type === 'text' && node.content.trim()) {
        element = Text(node.content.trim())
    }
    return element
}

const addChild = (rootTag, root, extra?: any) => {
    if (getValue(rootTag, 'children.length')) {
        rootTag.children.map((childTag) => {
            const child = createNode(childTag, extra)
            if (child) {
                addChild(childTag, child)
                child.appendTo(root)
            }
        })
    }
}

export const render = (template: string, mountedRoot: any, extra?: any) => {
    if (typeof template === 'string') {
        const ast = parse(template)
        if (ast && ast.length) {
            if (ast.length > 1) {
                console.info('the root should only be a tag. more than one will be ignored.')
            }

            const rootTag = ast[0]
            const root = createNode(rootTag, extra)
            addChild(rootTag, root, extra)
            
            if (mountedRoot && mountedRoot.addChild) {
                root.appendTo(mountedRoot)
            }
        }
    }
}
