import { CCInteger, Collider2D, Component, Contact2DType, find, instantiate, Label, Node, Prefab, sp, tween, UITransform, v3, view, _decorator } from 'cc';
import { BaseLayer } from '../../common/BaseLayer';
import { cocosUtil } from '../../utils/cocosUtil';
import { constants } from '../data/constants';
import { msgac } from '../data/msgac';
import { audioManager } from '../manager/audioManager';
import { designManager } from '../manager/designManager';
import { eventManager } from '../manager/eventManager';
import { iconManager } from '../manager/iconManager';
import { levelManager } from '../manager/levelManager';
import { resManager } from '../manager/resManager';
import { playerModel } from '../model/playerModel';
const { ccclass, property } = _decorator;

@ccclass('RoleItem')
export class RoleItem extends Component {

    @property({
        tooltip: "是否是BOSS"
    })
    isBoss = false;

    @property({
        type: CCInteger,
        tooltip: "打败怪物后掉落的宝箱金币数量或者宝箱金币数量"
    })
    coin = 0;

    @property({
        type: CCInteger,
        tooltip: "类型 -1:玩家 0:怪物 1:金币宝箱 2:商店 3:弓箭 4:战力倍增 5:装备 6:技能 7:大炮 8:滚石"
    })
    roleType = 0;

    @property({
        type: CCInteger,
        tooltip: "类型参数1" +
            "\n-1|0) 角色id" +
            "\n2) 0:装备商店  1:技能商店" +
            "\n3) 0:向右射箭  1:向左射箭" +
            "\n4) 0:加法  1:乘法" +
            "\n5) 1:武器  2:衣服" +
            "\n6) 技能id" +
            "\n7) 0:向右发射  1:向左发射" +
            "\n8) 0:向右滚动  1:向左滚动"
    })
    roleTypeP1 = 0;

    @property({
        type: CCInteger,
        tooltip: "类型参数2" +
            "\n2) 商店id" +
            "\n5) 装备等级"
    })
    roleTypeP2 = 0;

    // 关卡主视图组件
    levelLayer: BaseLayer;

    // 战力相关数值
    atk: number = 0;
    valLabel: Label;

    // 所在层数
    floor: number = 0;

    // 地板节点
    groundNode: Node;

    // 战力变化特效支持
    atkChangeInfo: any;

    atkNode: Node;
    atkBgNode: Node;

    bodyNode: Node;
    bodySkeleton: sp.Skeleton;

    // 弓箭节点
    arrowsNode: Node;
    // 炮弹节点
    bulletsNode: Node;

    // 机关是否已触发了
    hasEffect: boolean = false;

    // 怪物是否已阵亡
    dead: boolean = false;

    // 视频图标
    adNode: Node;

    start() {
        if (this.roleType == constants.roleItemTypes.arrow) {
            this.arrowsNode = find("arrows", this.node);
            this.arrowsNode.active = false;
            let collider = this.arrowsNode.getComponent(Collider2D);
            collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
        } else if (this.roleType == constants.roleItemTypes.dapao) {
            this.bulletsNode = find("bullets", this.node);
            this.bulletsNode.active = false;
            let collider = this.bulletsNode.getComponent(Collider2D);
            collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
        } else if (this.roleType == constants.roleItemTypes.gunshi) {
            let collider = this.node.getComponent(Collider2D);
            collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);

            let bodyNode = find("body", this.node);
            let bodyPos = bodyNode.getPosition();
            bodyPos.x = -15;
            if (this.roleTypeP1 == constants.arrowTypes.left) {
                bodyPos.x = 15;
            }
            this.bodyNode.position = bodyPos;
        }
    }

    init(groundNode: Node, floor: number, levelLayer: BaseLayer) {
        // 地板节点
        this.groundNode = groundNode;
        // 所在层数
        this.floor = floor;
        // 关卡主视图组件
        this.levelLayer = levelLayer;

        let bodyNode = find("body", this.node);
        this.bodyNode = bodyNode;
        if (bodyNode) {
            this.bodySkeleton = bodyNode.getComponent(sp.Skeleton);
        }

        this.node["isBoss"] = this.isBoss;
        this.adNode = find("ad", this.node);

        // 战力
        let atkNode = find("atk", this.node);
        if (atkNode) {
            this.valLabel = find("val", atkNode).getComponent(Label);
            let val = this.valLabel.string;
            if (val) {
                // 移除符号
                val = val.replace(/-|x|\+|X/g, "");
                this.atk = parseInt(val);
            }
            this.atkNode = atkNode;
            this.atkBgNode = find("bg", atkNode);
        }

        if (this.roleType == constants.roleItemTypes.equip) {
            // 装备图标替换
            let row = designManager.instance.getRowById(constants.tableName.equip, this.getEquipId());
            iconManager.instance.setSprite(bodyNode, row.icon);
            let bgNode = find("bg", this.node);
            bgNode.setPosition(0, bodyNode.getComponent(UITransform).height * 0.5);
            if (this.roleTypeP1 == constants.equipTypes.dress && this.roleTypeP2 == 1) {
                bodyNode.setScale(0.8, 0.8);
            }
            this.atkNode.setPosition(0, bodyNode.getComponent(UITransform).height + 20);
            // 上下动画
            cocosUtil.tweenUpDown(bodyNode);
            cocosUtil.tweenRotate(bgNode, 4);
            if (this.adNode && this.adNode.active) {
                cocosUtil.tweenUpDown(this.adNode);
            }
        }

        if (this.roleType == constants.roleItemTypes.atk) {
            if (this.roleTypeP1 == constants.atkChangeTypes.add) {
                this.playAnimation("a", true);
            } else if (this.roleTypeP1 == constants.atkChangeTypes.multi) {
                this.playAnimation("b", true);
            }
        } else if (this.roleType == constants.roleItemTypes.coinBox) {
            if (this.isBoss) {
                this.playAnimation(constants.animations.standBy2, true);
            } else {
                this.playAnimation(constants.animations.standBy1, true);
            }
        } else {
            this.playAnimation(constants.animations.standBy, true);
        }

        if (this.roleType == constants.roleItemTypes.skill) {
            // 技能图标替换
            let row = designManager.instance.getRowById(constants.tableName.skill, this.roleTypeP1);
            iconManager.instance.setSprite(bodyNode, row.icon);
        }

        levelLayer.addButtonListener(this.node);
    }

    onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D) {
        let roleItem = null;
        if (selfCollider.node.name == "arrows" && otherCollider.node.name != "arrows") {
            roleItem = otherCollider.node.getComponent(RoleItem);
        }
        if (selfCollider.node.name == "bullets" && otherCollider.node.name != "bullets") {
            roleItem = otherCollider.node.getComponent(RoleItem);
        }
        if (selfCollider.node.name == "role_gunshi" && otherCollider.node.name != "role_gunshi") {
            roleItem = otherCollider.node.getComponent(RoleItem);
        }

        if (!roleItem || roleItem.roleType != constants.roleItemTypes.monster) {
            return;
        }
        roleItem.playAnimation(constants.animations.hit, false, () => {
            roleItem.playAnimation(constants.animations.standBy, true);
        });
        roleItem.addAtk(-this.atk);
    }

    hasAd() {
        if (this.adNode && this.adNode.active) {
            return true;
        }
        return false;
    }

    hideAd() {
        if (this.adNode) {
            this.adNode.active = false;
        }
    }

    getEquipId() {
        let type = this.roleTypeP1;
        let lv = this.roleTypeP2;
        let roleId = playerModel.instance.getRoleId();

        let id = type * 1000 + roleId * 10 + lv;

        return id;
    }

    setBodyScale(scaleX: number, scaleY: number) {
        this.bodyNode.setScale(scaleX, scaleY);
    }

    playAnimation(name: string, isLoop?: boolean, cbComplete?: Function, cbEnd?: Function) {
        if (this.isDead() && name != constants.animations.die) {
            // 已阵亡
            return;
        }

        if (!this.bodySkeleton) {
            if (cbComplete) {
                cbComplete();
            }
            return;
        }

        if (!isLoop) {
            isLoop = false;
        }

        if (name == constants.animations.hit) {
            let obj: any = {};
            obj.pos = cocosUtil.convertToWorldSpace(this.node, true);
            eventManager.instance.send(msgac.showHitEffect, obj);
        }

        this.bodySkeleton.setAnimation(0, name, isLoop);
        this.bodySkeleton.setCompleteListener(() => {
            // 每次循环播放结束都会回调
            if (cbComplete) {
                cbComplete();
            }
        });
        this.bodySkeleton.setEndListener(() => {
            // 首次播放结束才会回调
            if (cbEnd) {
                cbEnd();
            }
        });

        audioManager.instance.onRolePlayAnimation(this, this.roleType, this.roleTypeP1, name);

    }

    // 玩家缩进传送门
    startOpenPortal(cb?: Function) {
        tween(this.bodyNode).to(0.2, {
            scale: v3(0, 0, 1)
        }).start();
        this.playAnimationPortal("1", cb);
    }

    // 玩家从传送门中跳出来
    playerAppearFromPortal(cb?: Function) {
        this.playAnimationPortal("2");
        this.playAnimation(constants.animations.chuansong, false, () => {
            if (cb) {
                cb();
            }
        });
    }

    playAnimationPortal(name: string, cb?: Function) {
        let portalNode = find("effect/portal", this.node);
        if (!portalNode) {
            if (cb) {
                cb();
            }
            return;
        }
        portalNode.active = true;

        let height = this.bodyNode.getComponent(UITransform).height;
        let s = 0.1;
        if (name == "2") {
            s = 0.7;
        }
        let pos = portalNode.getPosition();
        pos.y = height * s;
        portalNode.setPosition(pos);

        let portalSkeleton = portalNode.getComponent(sp.Skeleton);
        portalSkeleton.timeScale = 1.8;
        portalSkeleton.setAnimation(0, name, false);
        portalSkeleton.setCompleteListener(() => {
            if (cb) {
                cb();
            }
        });
    }

    // 金币宝箱掉落
    createCoinBox(cb?: Function, obj?: any) {
        if (this.coin <= 0) {
            if (cb) {
                cb();
            }
            return;
        }

        let bundle = constants.bundles.common;
        resManager.instance.loadAsset(bundle.name, bundle.roleBox, Prefab, () => { }, (err, prefab) => {
            let boxNode = instantiate(prefab);
            let parentNode = this.node.parent;
            let position = this.node.position;

            if (obj && obj.parentNode) {
                parentNode = obj.parentNode;
            }
            boxNode.parent = parentNode;

            if (obj && obj.worldPos) {
                position = cocosUtil.convertToNodeSpace(boxNode, obj.worldPos);
            }
            boxNode.position = position;

            let boxRoleItem = boxNode.getComponent(RoleItem);
            boxRoleItem.roleType = constants.roleItemTypes.coinBox;
            boxRoleItem.coin = this.coin;
            boxRoleItem.isBoss = this.isBoss;
            boxRoleItem.init(this.groundNode, this.floor, this.levelLayer);
            if (this.isBoss) {
                // 加个小手点击引导
                cocosUtil.addHand(boxNode, boxNode, (handNode) => {
                    boxRoleItem["handNode"] = handNode;
                    // 根据实际情况再进行微调
                    let pos = handNode.getPosition();
                    pos.x += 55;
                    pos.y -= 40;
                    handNode.setPosition(pos);
                    if (levelManager.instance.isSkip) {
                        levelManager.instance.onClickRoleItem(boxRoleItem.node);
                    }
                });
            }
            if (cb) {
                cb();
            }
        });
    }

    // 获得玩家应该站立的世界坐标
    getPlayerWorldPos(playerNode?: Node) {
        let pos = cocosUtil.convertToWorldSpace(this.node);
        let transform = this.node.getComponent(UITransform);

        // 额外增加的间距
        let dx = 0;

        // 消除玩家不同角色立绘宽度差异
        let dp = 0;
        // if (playerNode) {
        //     let playerTf = playerNode.getComponent(UITransform);
        //     dp = playerTf.width * (1 - playerTf.anchorX);
        // }

        if (this.isBodyScalePositive()) {
            pos.x -= (transform.width * transform.anchorX + dx + dp);
        } else {
            pos.x += (transform.width * transform.anchorX + dx + dp);
        }

        let posY = cocosUtil.convertToWorldSpace(this.groundNode).y;

        return v3(pos.x, posY, 0);
    }

    // 获得立绘是否按照图片正常显示，没有翻转
    isBodyScalePositive() {
        let scale = this.bodyNode.getScale();
        if (scale.x > 0) {
            return true;
        }
        return false;
    }

    // 增加战力，val如果为负数，就是减少战力
    addAtk(val: number) {
        if (this.roleType != constants.roleItemTypes.player && this.roleType != constants.roleItemTypes.monster) {
            return;
        }
        if (this.atkChangeInfo) {
            // 上次还未完成的，直接刷新，并且丢弃掉，以最新的一个计数为准
            this.setAtkVal(this.atk);
            if (this.atk <= 0) {
                this.showDeadEffect();
                return;
            }
        }

        audioManager.instance.playEffect(constants.audioNames.figure);

        this.atkChangeInfo = {};
        this.atkChangeInfo.atkStart = this.atk;

        // 先加上去，避免快速点击计算错误
        this.atk += val;
        if (this.atk < 0) {
            this.atk = 0;
        }

        this.atkChangeInfo.change = 1;
        if (val < 0) {
            val = -val;
            this.atkChangeInfo.change = -1;
        }

        let dVal = 1;
        let duration = constants.atkChangeTimeGap * val;
        while (duration > constants.atkChangeTimeMax) {
            dVal++;
            duration = constants.atkChangeTimeGap * Math.ceil(val / dVal);
        }

        this.atkChangeInfo.change *= dVal;
        this.atkChangeInfo.val = val;
        this.atkChangeInfo.count = 0;
    }

    closeHand() {
        if (this["handNode"]) {
            this["handNode"].destroy();
            delete this["handNode"];
        }
    }

    openBoxAward(cb: Function) {
        if (this.isBoss) {
            this.playAnimation(constants.animations.open2, false, cb);
        } else {
            this.playAnimation(constants.animations.open1, false, cb);
        }
    }

    showDeadEffect(cb?: Function, obj?: any) {
        this.dead = true;
        this.playAnimation(constants.animations.die, false, () => {
            if (cb) {
                cb();
            }
            this.createCoinBox(() => {
                if (!this.isPlayer()) {
                    // 移除敌人
                    this.node.destroy();
                    // 判断一下如果敌人全部阵亡，则弹出狩猎成功的界面
                    eventManager.instance.send(msgac.judgeLevelSuccess);
                }
            }, obj);
        });
    }

    isPlayer() {
        return this.roleType == constants.roleItemTypes.player;
    }

    setAtkVal(val?: number) {
        if (val == undefined) {
            val = this.atk;
        }
        this.valLabel.string = "" + val;

        if (this.isPlayer()) {
            let tf = this.atkBgNode.getComponent(UITransform);
            if (val >= 1000) {
                this.atkNode.setPosition(0, 240);
                tf.width = 120;
                tf.height = 120;
            } else if (val >= 100) {
                this.atkNode.setPosition(0, 230);
                tf.width = 90;
                tf.height = 90;
            } else {
                this.atkNode.setPosition(0, 220);
                tf.width = 70;
                tf.height = 70;
            }
        }
    }

    isDead(): boolean {
        if (this.roleType != constants.roleItemTypes.player && this.roleType != constants.roleItemTypes.monster) {
            return false;
        }
        if (this.dead || this.atk <= 0) {
            return true;
        }
        return false;
    }

    startGunShi(cb?: Function) {
        if (this.hasEffect) {
            return;
        }
        this.hasEffect = true;

        let posX = this.groundNode.getComponent(UITransform).width * 0.5;

        let toPos = this.node.getPosition();
        toPos.x = posX;
        if (this.roleTypeP1 == constants.arrowTypes.left) {
            toPos.x = -posX;
        }

        tween(this.node).to(1.25, {
            position: toPos
        }).call(() => {
            this.node.destroy();
            if (cb) {
                cb();
            }
        }).start();
    }

    /**
     * 发射大炮
     */
    shootBullets(cb?: Function) {
        if (this.hasEffect) {
            return;
        }
        this.hasEffect = true;

        this.bulletsNode.active = false;
        this.scheduleOnce(() => {
            this.bulletsNode.active = true;

            let pos = this.bulletsNode.getPosition();
            let toPos = v3(view.getVisibleSize().width, 0, 0);
            if (this.roleTypeP1 == constants.arrowTypes.left) {
                toPos = v3(-view.getVisibleSize().width, 0, 0);
                pos.x = -190;
            } else {
                pos.x = 190;
            }
            this.bulletsNode.setPosition(pos);

            tween(this.bulletsNode).by(0.8, {
                position: toPos
            }).call(() => {
                this.node.destroy();
                if (cb) {
                    cb();
                }
            }).start();
        }, 0.5);
    }

    /**
     * 射出弓箭
     */
    shootArrows(cb?: Function) {
        if (this.hasEffect) {
            return;
        }
        this.hasEffect = true;

        let arrowNode = find("arrows", this.node);
        arrowNode.active = false;
        this.scheduleOnce(() => {
            arrowNode.active = true;
            let pos = arrowNode.getPosition();
            pos.x += 50;
            arrowNode.setPosition(pos);

            let toPos = v3(view.getVisibleSize().width, 0, 0);
            if (this.roleTypeP1 == constants.arrowTypes.left) {
                toPos = v3(-view.getVisibleSize().width, 0, 0);
            }
            tween(this.arrowsNode).by(0.4, {
                position: toPos
            }).call(() => {
                this.node.destroy();
                if (cb) {
                    cb();
                }
            }).start();
        }, 0.5);
    }

    update(dt: number) {
        let info = this.atkChangeInfo;
        if (info) {
            info.count += dt;
            if (info.count >= constants.atkChangeTimeGap) {
                info.count -= constants.atkChangeTimeGap;
                let changeVal = info.change;
                if (changeVal > info.val) {
                    changeVal = info.val;
                }
                info.atkStart += changeVal;
                this.setAtkVal(info.atkStart);
                info.val -= Math.abs(changeVal);
                if (info.val <= 0) {
                    this.atkChangeInfo = null;
                    this.setAtkVal(this.atk);
                }
                if (info.atkStart <= 0) {
                    this.atkChangeInfo = null;
                    // 阵亡
                    this.showDeadEffect();
                }
            }
        }
    }

}

