import PIFS from "../PIFS";
import MatchView from "../Views/MatchView";
import Bot from "./Bot";
import EventType from "./EventType";
import Utils from "./Utils";

const {ccclass, property} = cc._decorator;

@ccclass
export default class Boy extends cc.Component {
    //unique
    index:number;

    //childNodes
    headphoto:cc.Node;
    arrow:cc.Node
    body:cc.Node;
    saw:cc.Node;
    fire:cc.Node;

    //components
    rigidBody:cc.RigidBody; 
    armatureDisplay:dragonBones.ArmatureDisplay;
    sawAnimate:cc.Animation;

    //properties
    speed:number = 400;
    acc:cc.Vec2 = cc.v2(0,0);
    angleCorrectSpeed = 150;
    color:cc.Color = cc.Color.WHITE;

    //flags
    attacking:boolean = false;
    isAutoAttack:boolean = true;
    onGround:number = 0;
    dead:boolean = false;
    bouncing:boolean = false;
    keepingRun:boolean = false;

    /**名次 */
    rankingNum:number;

    onLoad(){
        this.node.zIndex = 1;
        
        this.body = this.node.getChildByName('Body');
        this.fire = this.body.getChildByName('Fire');

        this.saw = this.body.getChildByName('Saw');
        this.saw.addComponent(Saw).boy = this;

        this.arrow = this.node.getChildByName('Arrow');
        this.headphoto = this.node.getChildByName('HeadPhoto'); 

        this.rigidBody = this.node.getComponent(cc.RigidBody);
        this.armatureDisplay = this.body.getComponent(dragonBones.ArmatureDisplay);
        this.sawAnimate = this.saw.getComponent(cc.Animation);

        //init
        this.armatureDisplay.timeScale = 2;
        this.armatureDisplay.playAnimation(this.getMoveName(),0);
        
        if(this.index==window.gameSystem.masterId){
            this.inActiveHeadPhoto();
            this.activeArrow();
            this.scheduleOnce(()=>{
                this.inActiveArrow();
                this.activeHeadPhoto();
            },1.5);
        }else{
            this.fire.active = false;
            this.activeHeadPhoto();
        }
    }

    getIdleName(){
        return 'daiji' + BoyColor.getColorWith_(this.index);
    }

    getMoveName(){
        return 'xingzou' + BoyColor.getColorWith_(this.index);
    }

    getHappName(){
        return 'bianlian' + BoyColor.getColorWith_(this.index);
    }

    addAcc(acc:cc.Vec2){
        this.acc = this.acc.add(acc);
    }

    subAcc(acc:cc.Vec2){
        this.acc = this.acc.sub(acc);
    }

    activeArrow(){
        this.arrow.active = true;
        this.arrow.getComponent(cc.Sprite).spriteFrame = 
            (PIFS.matchPlayerInfos[this.index].gender==1?
                window.rs.sf_arrowPink:
                window.rs.sf_arrowBlue
            );
        this.arrow.runAction(
            cc.repeatForever(cc.sequence(
                cc.spawn(cc.moveBy(0.15,cc.v2(0,15)),cc.scaleTo(0.15,0.9,1)),
                cc.spawn(cc.moveBy(0.15,cc.v2(0,-15)),cc.scaleTo(0.15,1,1)),
            ))
        );
    }

    inActiveArrow(){
        this.arrow.stopAllActions();
        this.arrow.active = false;
    }

    activeHeadPhoto(){
        this.headphoto.active = true;
        let avatar = this.headphoto.getChildByName("Mask").getChildByName("Avatar").getComponent(cc.Sprite);
        Utils.LoadSpriteFrame(PIFS.matchPlayerInfos[this.index].avatarUrl, (spriteFrame) => {
            avatar.spriteFrame = spriteFrame;
        });
        this.headphoto.runAction(cc.repeatForever(cc.sequence(
            cc.spawn(cc.moveBy(0.15,cc.v2(0,15)),cc.scaleTo(0.15,0.9,1)),
            cc.spawn(cc.moveBy(0.15,cc.v2(0,-15)),cc.scaleTo(0.15,1,1)),
        )));
    }

    inActiveHeadPhoto(){
        this.headphoto.active = false;
    }

    cancelRun(){
        this.keepingRun = false;
    }

    forward(direction:number){
        this.body.scaleX = direction * Math.abs(this.body.scaleX);
        if(this.onGround>0){
            this.keepingRun = true;
        }
    }

    move(){
        let basicAngle = this.body.scaleX < 0 ? 180 : 0;
        let radian = (basicAngle + this.body.angle) / 180 * Math.PI;
        this.rigidBody.linearVelocity = cc.v2(
            Math.cos(radian) * this.speed,
            Math.sin(radian) * this.speed
        );
    }

    jump(){
        this.keepingRun = false;
        if(this.body.scaleX<0){
            this.leftUp();
        }else if(this.body.scaleX>0){
            this.rightUp();
        }
    }

    up(){
        if(this.bouncing)return;
        this.keepingRun = false;
        this.rigidBody.linearVelocity = cc.v2(0,this.speed*1.5);
    }

    leftUp(){
        if(this.bouncing)return;
        this.body.scaleX = -1 * Math.abs(this.body.scaleX);
        this.rigidBody.linearVelocity = cc.v2(-this.speed*0.5,this.speed*1.5);
    }

    rightUp(){
        if(this.bouncing)return;
        this.body.scaleX = 1 * Math.abs(this.body.scaleX);
        this.rigidBody.linearVelocity = cc.v2(this.speed*0.5,this.speed*1.5);
    }

    attack(){
        if(!this.attacking){
            this.attacking = true;
            this.sawAnimate.play('Saw');
            cc.audioEngine.playEffect(window.rs.ac_attack,false);
        }
    }

    autoAttack(){
        if(this.isAutoAttack){
            return this.isAutoAttack = false;
        }else{
            return this.isAutoAttack = true;
        }
    }

    die(){
        if(this.dead)return;
        this.dead = true;
        let node = cc.instantiate(window.rs.pf_blood);
        node.setPosition(this.node.position);
        let armatureDisplay = node.getComponent(dragonBones.ArmatureDisplay);
        armatureDisplay.addEventListener(dragonBones.EventObject.COMPLETE,()=>{
            if(armatureDisplay.animationName=='blood1'){
                this.armatureDisplay.playAnimation('blood2',1);
            }
        });
        window.gc.bloodGroup.addChild(node);
        window.gm.removeBoy(this);
        cc.audioEngine.playEffect(window.rs.ac_bu,false);
    }

    update(dt:number){
        if(this.onGround>0){
            this.rigidBody.gravityScale = 5;

            if(window.gm.isGameOver){
                if(this.armatureDisplay.animationName!=this.getHappName()){
                    this.armatureDisplay.playAnimation(this.getHappName(),0);
                }
            }else{
                if(this.keepingRun){
                    this.move();
                    if(this.armatureDisplay.animationName!=this.getMoveName()){
                        this.armatureDisplay.playAnimation(this.getMoveName(),0);    
                    }
                }else{
                    if(this.armatureDisplay.animationName!=this.getIdleName()){
                        this.armatureDisplay.playAnimation(this.getIdleName(),0);    
                    }
                }
            }
        }else{
            this.rigidBody.gravityScale = 5;
            
            if(this.body.angle<0){
                let nextAngle = this.body.angle + this.angleCorrectSpeed*dt;
                if(nextAngle>0){
                    this.body.angle = 0;
                }else{
                    this.body.angle = nextAngle;
                }
            }else if(this.body.angle>0){
                let nextAngle = this.body.angle - this.angleCorrectSpeed*dt;
                if(nextAngle<0){
                    this.body.angle = 0;
                }else{
                    this.body.angle = nextAngle;
                }
            }

            if(this.armatureDisplay.animationName!=this.getMoveName()){
                this.armatureDisplay.playAnimation(this.getMoveName(),0);    
            }
        }

        let boyEntity = window.gameSystem.boys.find(boy => boy.id === this.index);

        if (this.isRunOnHost()) {
            this.rigidBody.type = cc.RigidBodyType.Dynamic;
            this.rigidBody.linearVelocity = this.rigidBody.linearVelocity.add(cc.v2(this.acc.x*dt,this.acc.y*dt));

            this.uploadFrame_state();
        } else {
            this.rigidBody.type = cc.RigidBodyType.Static;
            this.rigidBody.linearVelocity = cc.Vec2.ZERO;

            this.node.setPosition(this.node.position.lerp(boyEntity.position, 0.33));
            this.body.angle = boyEntity.angle;
            this.body.scaleX = boyEntity.scaleX;
        }

        if (boyEntity.dead) {
            this.node.setPosition(boyEntity.deadPosition);
            this.die();
        }
    }

    /**
     * bounce when a player step on another player
     * @param direction 1:up,-1:down
     */
    bounce(direction:number){
        this.bouncing = true;
        this.rigidBody.linearVelocity = cc.v2(0,direction*this.speed*1.5);
        this.scheduleOnce(()=>{
            this.bouncing = false;
        },0.1)
    }

    grounds:cc.Node[] = [];

    removeGround(ground:cc.Node){
        let arr = [];
        this.grounds.forEach((node:cc.Node)=>{
            if(ground!=node){
                arr.push(node);
            }
        });
        this.grounds = arr;
    }

    onCollisionEnter(other:cc.Collider){
        if(other.node.group==EventType.GROUP_GROUND){
            this.onGround++;
            this.grounds.push(other.node);
            if (this.isRunOnHost()) this.body.angle = other.node.angle; 
        }
        if(other.node.group==EventType.GROUP_BOY){
            if (this.isRunOnHost()) {
                let distance = this.node.y - other.node.y;
                if(distance<-25){
                    this.bounce(-1);
                }else if(distance>25){
                    this.bounce(1);
                }
            }
        }
    }

    onCollisionExit(other:cc.Collider){
        if(other.node.group==EventType.GROUP_GROUND){
            this.onGround--;
            this.removeGround(other.node);
            if (this.isRunOnHost()) {
                if(this.grounds.length>0){
                    this.body.angle = this.grounds[this.grounds.length-1].angle; 
                }
            }
        }
    }

    //======联机API======

    /**是否运行在主机上 */
    isRunOnHost() {
        if (window.gameSystem.masterId === this.index) {
            return true;
        }
        if (this.getComponent(Bot)) return true;
        return false;
    }
    
    /**上传帧-状态 */
    uploadFrame_state() {
        window.gm.socketPlayer.uploadFrames({
            t: 1,
            id: this.index,
            x: this.node.x.toFixed(3),
            y: this.node.y.toFixed(3),
            a: this.body.angle.toFixed(1),
            sx: this.body.scaleX.toFixed(3),
        });
    }

    /**上传帧-被杀 */
    uploadFrame_beKilled(killerId: number) {
        window.gm.socketPlayer.uploadFrames({
            t: 2,
            id: this.index,
            x: this.node.x.toFixed(1),
            y: this.node.y.toFixed(1),
            ki: killerId 
        });
    }
}
class BoyColor {
    static colors = ['red','green','blue','yellow'];
    static mapColors = [cc.Color.RED,cc.Color.GREEN,cc.Color.BLUE,cc.Color.YELLOW];

    static getColorWith_(index:number){
        return '_' + BoyColor.colors[index];
    }
}
class Saw extends cc.Component{
    boy:Boy;

    onCollisionStay(other:cc.Collider){
        if(other.node==this.boy.node||other.node.group==EventType.GROUP_GROUND)return;

        if(other.node.group==EventType.GROUP_SAW){
            if(this.boy.autoAttack){
                this.boy.attack();
            }
            return;
        }
        if(other.node.group==EventType.GROUP_BOY){
            if(this.boy.autoAttack){
                this.boy.attack();
            }
            if(this.boy.attacking){
                let otherBoy = other.getComponent(Boy);
                this.kill(otherBoy);
            }
            return;
        }
    }

    kill(otherBoy:Boy){
        if(otherBoy){
            if(this.boy.node.y>=otherBoy.node.y){
                if(!this.boy.dead){
                    if (otherBoy.isRunOnHost()) otherBoy.uploadFrame_beKilled(this.boy.index);
                }       
            }
        }
    }

    attackFinish(){
        this.boy.attacking = false;
    }
}

