// Learn TypeScript:
//  - https://docs.cocos.com/creator/manual/en/scripting/typescript.html
// Learn Attribute:
//  - https://docs.cocos.com/creator/manual/en/scripting/reference/attributes.html
// Learn life-cycle callbacks:
//  - https://docs.cocos.com/creator/manual/en/scripting/life-cycle-callbacks.html

import ConfigManager from "../../../engines/configs/ConfigManager";
import { GUIManager } from "../../../engines/gui/GUIManager";
import JLoader from "../../../engines/loader/JLoader";
import LoadingView from "../../../engines/loadingView/LoadingView";
import MathUtils from "../../../engines/utils/MathUtils";
import ConfigKeys from "../../models/ConfigKeys";
import GameModel from "../../models/GameModel";
import UIKeys from "../../UIKeys";
import InCirclePolygon from "./InCirclePolygon";
import PlayerController from "./PlayerController";

const {ccclass, property} = cc._decorator;

@ccclass
export default class GameController extends cc.Component {

    @property(cc.Node)
    camera: cc.Node = null;

    @property(cc.Node)
    polygon: cc.Node = null;

    @property(PlayerController)
    player: PlayerController = null;

    @property(cc.MeshRenderer)
    background:cc.MeshRenderer=null;

    /**
     * 游戏结束
     */
    isGameOver:boolean;

    private inCirclePolygon:InCirclePolygon;

    private isDrop:boolean; 
    private startDropTime:number;
    /**
     * 移动向量
     */
    private moveVec:cc.Vec3=new cc.Vec3();

    levelConfig:any;
    carConfig:any;

    start () {
        GameController.__instance=this;
        //显示进度条
        LoadingView.single.Show();
        //关卡配置
        let levelConfigs:any[]=ConfigManager.single.GetConfigList(ConfigKeys.Levels);
        cc.log(GameModel.single.currentLevel);
        let level:number=GameModel.single.currentLevel%levelConfigs.length;
        if(level==0){
            level=1;
        }
        this.levelConfig=ConfigManager.single.GetConfigItem(ConfigKeys.Levels,level);
        //汽车配置
        this.carConfig=ConfigManager.single.GetConfigItem(ConfigKeys.Car,GameModel.single.currentCarId);
        this.LoadPolygon();
    }
    private loader:JLoader;
    private LoadPolygon():void{
        this.loader=new JLoader();
        this.loader.AddEvent(JLoader.EVENT_COMPLETE,this,this.PolygonLoaded);
        this.loader.Load(this.levelConfig.packageName,this.levelConfig.polygonPrefab);
    }

    private PolygonLoaded():void{
        let prefab:cc.Prefab=this.loader.GetContent(cc.Prefab) as cc.Prefab;
        let node:cc.Node=cc.instantiate(prefab);
        this.polygon.addChild(node);

        this.loader.RemoveAllEvent();
        this.loader.AddEvent(JLoader.EVENT_COMPLETE,this,this.CarLoaded);
        this.loader.Load(this.carConfig.packageName,this.carConfig.prefab);
    }

    private CarLoaded():void{
        let prefab:cc.Prefab=this.loader.GetContent(cc.Prefab) as cc.Prefab;
        let node:cc.Node=cc.instantiate(prefab);
        this.player.node.addChild(node);
        //喷气粒子
        this.player.particle=cc.find("ParticleRoot",node);
        if(this.player.particle!=null){
            this.player.particle.active=false;
        }

        this.loader.RemoveAllEvent();
        this.loader.AddEvent(JLoader.EVENT_COMPLETE,this,this.BackgroundLoaded);
        this.loader.Load("background",this.levelConfig.background);
    }

    private BackgroundLoaded():void{
        this.loader.RemoveAllEvent();
        let texture:cc.Texture2D=this.loader.GetContent(cc.Texture2D) as cc.Texture2D;
        let m:cc.Material=this.background.getMaterial(0);
        m.setProperty("diffuseTexture",texture);
        this.loader=null;
        this.InitGame();
        LoadingView.single.Hide();
    }

    private InitGame():void{
        this.inCirclePolygon=new InCirclePolygon(this.polygon);
        this.StartGame();
    }

    /**
     * 开始游戏
     */
    StartGame():void{
        if(this.player.particle!=null){
            this.player.particle.active=false;
        }
        this.isGameOver=false;
        this.isDrop=false;
        this.inCirclePolygon.Reset();
        this.player.Reset();
    }

    update (dt:number) {
        if(this.inCirclePolygon==null){
            return;
        }
        if(this.isGameOver){
            return;
        }
        cc.Vec3.zero(this.moveVec);
        //前进的速度
        cc.Vec3.add(this.moveVec,this.moveVec,this.player.speed);
        if(this.isDrop){
            cc.Vec3.add(this.moveVec,this.moveVec,this.player.dropSpeed);
        }else{
            if(this.player.isLeft){
                cc.Vec3.add(this.moveVec,this.moveVec,this.player.leftSpeed);
            }else if(this.player.isRight){
                cc.Vec3.add(this.moveVec,this.moveVec,this.player.rightSpeed);
            }
            //冲刺
            if(this.player.isSprint){
                cc.Vec3.add(this.moveVec,this.moveVec,this.player.sprintSpeed);
            }
        }
        cc.Vec3.multiplyScalar(this.moveVec,this.moveVec,dt);
        //角色移动
        let pos:cc.Vec3=this.player.logicPosition;
        pos.add(this.moveVec,pos);
        //将X轴环形映射
        pos.x=MathUtils.CircularMapping(pos.x,this.inCirclePolygon.maxX,this.inCirclePolygon.minX);
        this.player.logicPosition=pos;

        //背景跟角色使用保持固定的距离
        pos=this.background.node.position;
        pos.z=0-(this.player.logicPosition.y+1000);
        this.background.node.position=pos;

        //摄像机跟随
        if(!this.isDrop){
            pos=this.camera.position;
            pos.x=this.player.logicPosition.x;
            pos.y=this.inCirclePolygon.center.y;
            pos.z=-this.player.logicPosition.z+50;
            this.camera.position=pos;
            // cc.log("摄像机位置：",pos.x,pos.y,pos.z);
        }
        //物理计算
        if(!this.isDrop&&this.player.isSprint==false){
            this.CheckPhysicsPos();
        }
        this.CheckAngle();
        //多边形更新
        this.inCirclePolygon.Update(dt);

        //检测游戏是否结束
        if(this.isGameOver==false){
            if(this.isDrop){
                let currentTime:number=cc.sys.now();
                if(currentTime-this.startDropTime>2000){
                    cc.log("游戏结束！");
                    this.GameOver(false);
                }
            }else{
                if(this.player.logicPosition.z>this.levelConfig.endPos){
                    cc.log("到达终点");
                    this.GameOver(true);
                }
            }
        }
    }

    GameOver(isWin:boolean):void{
        this.isGameOver=true;
        GUIManager.single.Show(UIKeys.WXS04,true);
        if(isWin){
            GameModel.single.currentLevel++;
            GameModel.single.SaveToLoacl();
        }
    }

    private rectsTemp:number[];
    private point:cc.Vec3=new cc.Vec3();
    private origin:cc.Vec3=new cc.Vec3();
    /**
     * 计算角度
     */
    private CheckAngle():void{
        if(this.rectsTemp==null){
            this.rectsTemp=[];
        }
        this.inCirclePolygon.PolygonIntersects(this.player.rect,this.rectsTemp);
        if(this.rectsTemp.length==0){
            return;
        }
        if(this.rectsTemp.length>2){
            cc.error("主角的大小太大了！");
            return;
        }
        let angle:number;
        //在单独的一个块中
        if(this.rectsTemp.length==1){
            angle=this.inCirclePolygon.GetPolygonTileAngle(this.rectsTemp[0]);
            let aTile:cc.Rect=this.inCirclePolygon.GetPolygonTile(this.rectsTemp[0]);
            this.inCirclePolygon.SetAngle(angle);
            this.background.node.angle=angle;
            this.inCirclePolygon.SetCenter(aTile.x+aTile.width*0.5,this.inCirclePolygon.centerHeight,0);
        }else{//跨块了
            let aAngle:number=this.inCirclePolygon.GetPolygonTileAngle(this.rectsTemp[0]);
            let bAngle:number=this.inCirclePolygon.GetPolygonTileAngle(this.rectsTemp[1]);
            let aTile:cc.Rect=this.inCirclePolygon.GetPolygonTile(this.rectsTemp[0]);
            //计算出旋转点
            let cx:number=aTile.x+aTile.width;
            let helfWidth:number=this.player.width*0.5;
            let sx:number=cx-helfWidth;
            let ex:number=cx+helfWidth;
            let proportion:number=(this.player.logicPosition.x-sx)/(ex-sx);
            angle=aAngle+(bAngle-aAngle)*proportion;
            this.inCirclePolygon.SetAngle(angle);
            this.background.node.angle=angle;
            
            //绕点
            this.origin.x=cx;
            this.origin.y=0;
            this.origin.z=0;
            //原始的圆心
            this.point.x=aTile.x+(aTile.width*0.5);
            this.point.y=this.inCirclePolygon.centerHeight;
            this.point.z=0;
            angle=0-this.inCirclePolygon.outAngle*proportion;
            this.inCirclePolygon.RotationCenter(angle,this.point,this.origin);
        }
    }

    //物理坐标
    private physicsPos:cc.Vec2=new cc.Vec2();
    private CheckPhysicsPos():void{
        let list:cc.Vec3[]=this.player.gridView;
        let count:number=0;
        let point:cc.Vec3;
        let state:number
        for (let index = 0; index < list.length; index++) {
            point=list[index];
            this.inCirclePolygon.GetPhysicsPos(point.x,point.z,this.physicsPos);
            state=this.inCirclePolygon.GetPhysicsState(this.physicsPos.x,this.physicsPos.y);
            if(state==0){
                count++;
            }
        }
        //超过半数悬空则掉落
        if(count>=5){
            this.isDrop=true;
            this.startDropTime=cc.sys.now();
        }
    }

    onDestroy():void{
        let list:string[]=[
            this.levelConfig.packageName,
            this.carConfig.packageName,
            "background"
        ]
        let bundle:cc.AssetManager.Bundle;
        list.forEach(bundleName => {
            bundle=cc.assetManager.getBundle(bundleName);
            bundle.releaseAll();
            cc.assetManager.removeBundle(bundle);
        });
    }

    private static __instance:GameController;
    public static get single():GameController{
        return this.__instance;
    }
}
