import EMeshType from "./enum/EMeshType.js"
import BillboardStatus from "./enum/BillboardStatus.js"
import Logger from "./Logger.js"

const logger = new Logger('XAvatarBillboardComponent')

export default class XAvatarBillboardComponent {
    constructor(e) {
        E(this, "_nickName", "");
        E(this, "_words", "");
        E(this, "_isNameVisible", !0);
        E(this, "_isBubbleVisible", !0);
        E(this, "_isGiftButtonsVisible", !1);
        E(this, "withinVisualRange", !1);
        E(this, "_bubble");
        E(this, "_nameBoard");
        E(this, "_giftButtons", new Map);
        E(this, "_buttonTex", new Map);
        E(this, "_nameLinesLimit", 2);
        E(this, "_nameLengthPerLine", 16);
        E(this, "_scene");
        E(this, "_pickBbox", null);
        E(this, "bbox");
        E(this, "_height", .26);
        E(this, "_attachmentObservers", new Map);
        E(this, "attachToAvatar", (e,t,r=!1,n={
            x: 0,
            y: 0,
            z: 0
        },o=!1,a,s)=>{
            const l = e.rootNode;
            if (this.bbox || e.getBbox(),
            t && l) {
                const u = a || t.uniqueId;
                let c = this._attachmentObservers.get(u);
                if (c)
                    if (o)
                        this._scene.onBeforeRenderObservable.remove(c),
                        this._attachmentObservers.delete(u);
                    else
                        return;
                const h = ue4Position2Xverse(n);
                r ? (t.setParent(l),
                t.position = h) : (c = this._scene.onBeforeRenderObservable.add(()=>{
                    let f = 0;
                    s ? (f = e.rootNode.rotation.y / Math.PI * 180 + 90,
                    e.rootNode.rotation.y && (t.rotation.y = e.rootNode.rotation.y)) : f = e.avatarManager.sceneManager.cameraComponent.getCameraPose().rotation.yaw,
                    f || (f = 0);
                    const d = new BABYLON.Vector3(0,this._height,0);
                    e.controller && e.controller.activeAnimation() && e.controller.activeAnimation().animatables[0] && (this._height = d.y = (e.controller.activeAnimation().animatables[0].target.position.y * .01 - .66) * e.scale),
                    d.y < .07 * e.scale && (d.y = 0),
                    t.position.x = l.position.x + h.x * Math.sin(f * Math.PI / 180) + h.z * Math.cos(f * Math.PI / 180),
                    t.position.z = l.position.z + h.x * Math.cos(f * Math.PI / 180) - h.z * Math.sin(f * Math.PI / 180),
                    t.position.y = l.position.y + this.bbox.maximum.y + h.y + d.y
                }
                ),
                this._attachmentObservers.set(u, c))
            } else
                logger.error("avatar or attachment not found!")
        }
        );
        E(this, "detachFromAvatar", (e,t,r=!1)=>{
            const n = this._attachmentObservers.get(t.uniqueId);
            n && this._scene.onBeforeRenderObservable.remove(n),
            e.rootNode ? (t.setEnabled(!1),
            t.parent = null,
            r && t.dispose()) : logger.error("avatar not found!")
        }
        );
        E(this, "getBbox", (e,t={})=>{
            const {isConst: r=!1, changeWithAvatar: n=!1} = t;
            let {localCenter: o={
                x: 0,
                y: 0,
                z: 75
            }, width: a=1.32, height: s=1.5, depth: l=.44} = t;
            if (n) {
                const u = e.scale;
                o = {
                    x: o.x * u,
                    y: o.y * u,
                    z: o.z * u
                },
                a *= u,
                s *= u,
                l *= u
            }
            if (e.rootNode) {
                let u = new BABYLON.Vector3(0,0,0)
                  , c = new BABYLON.Vector3(0,0,0);
                if (r) {
                    const f = ue4Position2Xverse(o);
                    u = u.add(f.add(new BABYLON.Vector3(-a / 2,-s / 2,-l / 2))),
                    c = c.add(f.add(new BABYLON.Vector3(a / 2,s / 2,l / 2)))
                } else if (u = u.add(new BABYLON.Vector3(Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY)),
                c = c.add(new BABYLON.Vector3(Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY)),
                e.isRender) {
                    e.rootNode.getChildMeshes().forEach(_=>{
                        const g = _.getBoundingInfo().boundingBox.minimum
                          , m = _.getBoundingInfo().boundingBox.maximum;
                        u.x = Math.min(u.x, g.x),
                        c.x = Math.max(c.x, m.x),
                        u.y = Math.min(u.y, g.y),
                        c.y = Math.max(c.y, m.y),
                        u.z = Math.min(u.z, g.z),
                        c.z = Math.max(c.z, m.z)
                    }
                    );
                    const f = c.x - u.x
                      , d = c.z - u.z;
                    u.x -= e.scale * f / 2,
                    c.x += e.scale * f / 2,
                    c.y *= e.scale,
                    u.z -= e.scale * d / 2,
                    c.z += e.scale * d / 2
                } else {
                    const f = e.avatarManager.getMainAvatar();
                    f && f.bbComponent.bbox && (u.x = f.bbComponent.bbox.minimum.x,
                    c.x = f.bbComponent.bbox.maximum.x,
                    u.y = f.bbComponent.bbox.minimum.y,
                    c.y = f.bbComponent.bbox.maximum.y,
                    u.z = f.bbComponent.bbox.minimum.z,
                    c.z = f.bbComponent.bbox.maximum.z)
                }
                const h = e.rootNode.computeWorldMatrix(!0);
                if (this.bbox ? this.bbox.reConstruct(u, c, h) : this.bbox = new BABYLON.BoundingBox(u,c,h),
                this._pickBbox == null) {
                    const f = this.createPickBoundingbox(e, this.bbox);
                    this.attachToAvatar(e, f.data, !1, {
                        x: 0,
                        y: 0,
                        z: 0
                    }, !1, "pickbox"),
                    this._pickBbox = f
                }
            } else
                logger.error("avatar not found!")
        }
        );
        this._scene = e
    }
    get isNameVisible() {
        return this._isNameVisible
    }
    get isBubbleVisible() {
        return this._isBubbleVisible
    }
    get isGiftButtonsVisible() {
        return this._isGiftButtonsVisible
    }
    get words() {
        return this._words
    }
    get nickName() {
        return this._nickName
    }
    get giftButtons() {
        return this._giftButtons
    }
    get bubble() {
        return this._bubble
    }
    get nameBoard() {
        return this._nameBoard
    }
    setNicknameStatus(e) {
        if (this.nameBoard && this.nameBoard.setStatus(e),
        e == BillboardStatus.DISPOSE) {
            const t = this._attachmentObservers.get("nickname");
            t && (this._scene.onBeforeRenderObservable.remove(t),
            this._attachmentObservers.delete("nickname"))
        }
    }
    setBubbleStatus(e) {
        if (this.bubble && this.bubble.setStatus(e),
        e == BillboardStatus.DISPOSE) {
            const t = this._attachmentObservers.get("bubble");
            t && (this._scene.onBeforeRenderObservable.remove(t),
            this._attachmentObservers.delete("bubble"))
        }
    }
    setButtonsStatus(e) {
        this.giftButtons && this.giftButtons.size != 0 && this.giftButtons.forEach(t=>{
            if (t.setStatus(e),
            e == BillboardStatus.DISPOSE && t.getMesh()) {
                const r = "button_" + t.getMesh().xid
                  , n = this._attachmentObservers.get(r);
                n && (this._scene.onBeforeRenderObservable.remove(n),
                this._attachmentObservers.delete(r))
            }
        }
        )
    }
    setGiftButtonsVisible(e) {
        this.setButtonsStatus(e ? BillboardStatus.SHOW : BillboardStatus.DISPOSE)
    }
    dispose(e) {
        this._attachmentObservers.forEach(t=>{
            this._scene.onBeforeRenderObservable.remove(t)
        }
        ),
        this._attachmentObservers.clear(),
        this.updateBillboardStatus(e, BillboardStatus.DISPOSE),
        this._buttonTex.clear(),
        this._pickBbox && (e.avatarManager.bboxMeshPool.release(this._pickBbox),
        this._pickBbox = null)
    }
    updateBillboardStatus(e, t) {
        this.bbox || e.getBbox(),
        e.isRender ? (e.setBubbleStatus(t),
        e.setButtonsStatus(t),
        e.setNicknameStatus(t)) : (e.setBubbleStatus(BillboardStatus.DISPOSE),
        e.setButtonsStatus(BillboardStatus.DISPOSE),
        e.enableNickname ? e.setNicknameStatus(t) : e.setNicknameStatus(BillboardStatus.DISPOSE))
    }
    disposeBillBoard(e) {
        this._attachmentObservers.forEach(t=>{
            this._scene.onBeforeRenderObservable.remove(t)
        }
        ),
        this._attachmentObservers.clear(),
        this.updateBillboardStatus(e, BillboardStatus.DISPOSE),
        this._buttonTex.clear(),
        this._pickBbox && (e.avatarManager.bboxMeshPool.release(this._pickBbox),
        this._pickBbox = null)
    }
    setPickBoxScale(e) {
        this._pickBbox && this._pickBbox.data && (this._pickBbox.data.scaling = new BABYLON.Vector3(e,e,e))
    }
    setIsPickable(e, t) {
        e.rootNode && e.rootNode.getChildMeshes().forEach(r=>{
            r.isPickable = t
        }
        ),
        this._pickBbox && this._pickBbox.data && (this._pickBbox.data.isPickable = t)
    }
    initNameboard(e, t=1) {
        this._nameBoard == null && (this._nameBoard = e.avatarManager.sceneManager.billboardComponent.addBillboard("name-" + e.id, !1, !0)),
        this._nameBoard.init("nickname", t / 300, t / 300)
    }
    initBubble(e, t=1) {
        this._bubble == null && (this._bubble = e.avatarManager.sceneManager.billboardComponent.addBillboard("bubble-" + e.id, !1, !0)),
        e.isRender && this._bubble.init("bubble", t / 250, t / 250)
    }
    say(e, t=this._words, {id: r, isUser: n, background: o, font: a="Arial", fontsize: s=38, fontcolor: l="#ffffff", fontstyle: u="bold", linesize: c=22, linelimit: h, offsets: f={
        x: 0,
        y: 0,
        z: 40
    }, scale: d, compensationZ: _=11.2, reregistAnyway: g=!0}) {
        (!this.bubble || this.bubble.getMesh() == null) && e.initBubble(),
        this._words = t;
        let m;
        n != null && (m = n ? XBillboardManager.userBubbleUrls : XBillboardManager.npcBubbleUrls),
        this._bubble && (this._bubble.DEFAULT_CONFIGS = {
            id: r,
            isUser: n,
            background: o || m,
            font: a,
            fontsize: s,
            fontcolor: l,
            fontstyle: u,
            linesize: c,
            linelimit: h,
            offsets: f,
            scale: d,
            compensationZ: _,
            reregistAnyway: g
        },
        this._bubble.getMesh() && (this._bubble.drawBillboard({
            imageList: o || m
        }, {
            texts: this._words,
            font: a,
            fontsize: s,
            fontcolor: l,
            fontstyle: u,
            linesize: c
        }, {
            offsets: f,
            scale: d,
            compensationZ: _
        }),
        this.attachToAvatar(e, this._bubble.getMesh(), !1, this._bubble.offsets, g, "bubble"),
        r && this._bubble.setId(r))),
        this.setButtonsStatus(BillboardStatus.DISPOSE)
    }
    silent() {
        this.setBubbleStatus(BillboardStatus.DISPOSE),
        this._words = ""
    }
    setNickName(e, t, {id: r, isUser: n, background: o, font: a="Arial", fontsize: s=40, fontcolor: l="#ffffff", fontstyle: u="bold", linesize: c=22, linelimit: h, offsets: f={
        x: 0,
        y: 0,
        z: 15
    }, scale: d, compensationZ: _=0, reregistAnyway: g=!1}) {
        this._nickName = t,
        (!this.nameBoard || this.nameBoard.getMesh() == null) && this.initNameboard(e),
        this._nameBoard && this._nameBoard.getMesh() && (this._nameBoard.DEFAULT_CONFIGS = {
            id: r,
            isUser: n,
            background: o,
            font: a,
            fontsize: s,
            fontcolor: l,
            fontstyle: u,
            linesize: c,
            linelimit: h,
            offsets: f,
            scale: d,
            compensationZ: _,
            reregistAnyway: g
        },
        this._nameBoard.drawBillboard({}, {
            texts: this._nickName,
            font: a,
            fontsize: s,
            fontcolor: l,
            fontstyle: u,
            linesize: c,
            linelimit: h
        }, {
            offsets: f,
            scale: d,
            compensationZ: 0
        }),
        this.attachToAvatar(e, this._nameBoard.getMesh(), !1, this._nameBoard.offsets, g, "nickname"),
        r && this._nameBoard.setId(r))
    }
    generateButtons(e, t=null, r, n=85) {
        if (t && (this._buttonTex = t,
        this.clearButtons()),
        this._buttonTex.size == 0)
            return;
        let o = (this._buttonTex.size - 1) / 2;
        this._buttonTex.forEach((a,s)=>{
            let l = this._giftButtons.get(s);
            l || (l = e.avatarManager.sceneManager.billboardComponent.addBillboard("button-" + s + e.id, !0, !1),
            l.init(s, r / 240, r / 240));
            const u = {
                x: r * o * 70,
                y: 0,
                z: r * (n - 20 * (o * o))
            };
            l.drawBillboard({
                imageList: [a]
            }, {}, {
                offsets: u,
                scale: r
            }),
            this.attachToAvatar(e, l.getMesh(), !1, l.offsets, !0, "button_" + s),
            this._giftButtons.set(s, l),
            o -= 1
        }
        ),
        this.setBubbleStatus(BillboardStatus.DISPOSE)
    }
    clearButtons() {
        this._giftButtons.forEach(e=>{
            e.dispose()
        }
        ),
        this._giftButtons.clear()
    }
    createPickBoundingbox(e, t) {
        const r = t.extendSize.x * 2
          , n = t.extendSize.y * 2
          , o = t.extendSize.z * 2
          , a = this._scene
          , s = Math.max(r, o)
          , l = e.avatarManager.bboxMeshPool.getFree(a, s, n, s)
          , u = l.data;
        return u && (u.position = t.centerWorld,
        u.setEnabled(!1),
        u.isPickable = !0,
        u.xtype = EMeshType.XAvatar,
        u.xid = e.id),
        l
    }
}