class Player{
    constructor(w, h, image, dx, type, name, frameWidth = 224, frameHeight = 214,
        frameSpeed = 1, size = 1){
        if(type == "bot"){
            this.direction = '_Left';
        }
        else{
            this.direction = '_Right';
        }
        this.size = size;
        this.x = w / 10 + dx;
        this.y = canvas.height - this.frameHeight / 2;
        this.frameWidth = frameWidth;
        this.frameHeight = frameHeight;
        this.currentFrame = 0;        
        this.currentAction = "stand" + this.direction;
        this.frameSpeed = frameSpeed;
        this.speed = 30;
        this.dx = 0;
        this.dy = 0;
        this.image = image;
        this.stopped = false; // блокировка передвижения
        this.stopCount = 0; // счетчик блокировки передвижения, по достижении нужного значения
        // персонаж снова сможет передвигаться
        this.nemesis = null; // противник
        this.type = type; // тип персонажа: игрок или робот
        this.name = name;
        this.idleCount = 0; // счтечик бездействия
        this.maxIdle = 60;
        this.min_distance = 70; // минимальное значение дистанции коллизии
        this.max_distance = 300; // максимальное значение дистанции коллизии
        this.health = {
            max: 100,
            current: 100
        }
        this.rage = { //Ярость
            max: 100,
            current: 0,
        }
        this.stunCount = 0; // оглушение, когда соперник бьет критом после накопления яорсти
        this.coolDown = 0; // кулдаун на все действия после обычного действия, например, блока
        this.coolDownArray = []; // массив кулдаунов конкретных ударов
    }
    collision(){
        if(this.type == "bot"){
            this.potential_nemesis = game.player;
        }
        else{
            this.potential_nemesis = game.characters.enemy;            
        }

        // бот всегда смотрит в сторону игрока
        if(this.type == "bot" && this.potential_nemesis){        
            if(this.potential_nemesis.x <= this.x){
                this.direction = "_Left";
            }
            else{
                this.direction = "_Right";                 
            }
        }

        if(this.potential_nemesis){
            this.collision_distance = Math.abs(this.potential_nemesis.x - this.x);            
        }

        // переходим в остояние боя, если дистанция меньше определенного значения
        if(this.collision_distance <= this.min_distance){                
            if(!this.potential_nemesis.dy && !this.dy){ // Если мы в прыжке, то коллизия не срабатывает
                this.nemesis = this.potential_nemesis;

                if(this.stopCount >= 5){
                    this.stopped = false;                 
                }
                else if(this.nemesis.stunCount == 0){
                    if(!this.stopped){
                        this.stopCount = 1;                        
                    }
                    this.stopped = true;                                        
                }
                if(this.stopCount > 10){
                    this.stopCount = 1;                     
                }      
                if(this.stopCount > 0){
                    this.stopCount++;
                }
            }              
        }
        else if(this.nemesis){ // вышли из коллизии           
            this.nemesis = null;
            this.stopped = false;
            this.stopCount = 0;             
        }
        if(this.collision_distance < this.max_distance){
            this.idleCount = 0;
        }
        if(this.collision_distance < this.max_distance || this.idleCount > this.maxIdle){

        }
        else{
            this.stopped = false;  
            this.stopCount = 0;              
        }
    }
    update(){
        if(!game.intro){
            this.idleCount++;            
        }

        if(this.type == "player"){
            const action = Object.keys(key_down)[Object.keys(key_down).length - 1]; 

            if(action){
                // Вызываем действие, если кнопка нажата и действие еще не выполнено
                // либо кнопка зажата и мы идем
                // При этом предыдущее действие либо закончено (т.е. currentFrame == 0),
                // либо мы стоим, прыгаем или присели (т.е. действия не once и не no_return)
                if( (key_down[action] != false || action.split("_")[0] == "walk")
                    &&  (this.currentFrame == 0
                        || !frame_data[this.name][this.currentAction].once
                        || (frame_data[this.name][this.currentAction].no_return
                            &&
                            this.currentFrame >= frame_data[this.name][this.currentAction].end - frame_data[this.name][this.currentAction].start - 1
                            )
                        ) 
                    ){

                    if(action.split("_")[0] != "walk"){
                        key_down[action] = false                        
                    } 

                    if( !( action.split("_")[0] == "walk" && this.currentAction == "walk" + this.direction ) ){
                        // console.log(this.currentAction, this.currentFrame)
                        this.doAction(action);                      
                    }
                }              
            }

            // Если идем, и нажата кнопка, лействие которой не jump и не walk
            if(
                    key_down["walk" + this.direction]
                    && this.currentAction.split("_")[0] != "walk"
                    && this.currentAction.split("_")[0] != "jump"

                    ||

                    this.currentAction == "walk" + this.direction
                    && !key_down[this.currentAction]
                
                ){
                this.dx = 0;
            }

        }

        if(this.stunCount && this.stunCount <= 2){
            this.stunCount++;
                const count = 5; // число шагов (чем выше, тем быстрее)
                // Если противник кританул, нас отталкивает за дистанцию боя,
                //  то есть меняется dx, замедляясь к концу движения
                if(this.nemesis && this.stunCount > 0 && this.stunCount < count){
                    this.nemesis.stopped = false;
                    this.doAction('stand' + this.direction);
                    // косинус менятеся от 1 (при аргументе 0) до 0 (при аргументе Math.PI/2)
                    // this.stunCount изначальо будет равен 2, поэтому чтобы получить ноль, пишем this.stunCount-2
                    // делим Math.PI / 2 на count и получаем число секторов, которые надо тпройти
                    // 27 — целое число, при умножении на которое при count = 5 получим целое число, ближайшее к 71 (дистанция боя)
                    // 71 = x * ( Math.cos( 0 * Math.PI / 2 / 5) + Math.cos( 1 * Math.PI / 2 / 5) + Math.cos( 2 * Math.PI / 2 / 5) )
                    //  x = 71 / 2.7 = 27
                    this.nemesis.dx = 27 * directions[this.nemesis.direction] * -1 * Math.cos( (this.stunCount - 2) * Math.PI / 2 / count)
                    // console.log(this.nemesis.dx, this.stunCount)
                }

        }
        else{
            this.stunCount = 0;
        }

        if(this.coolDown && this.coolDown <= 2){
            this.coolDown++;            
        }
        else{
            this.coolDown = 0;
        }

        this.collision();

        const my_action_params = frame_data[this.name][this.currentAction];
        if(!game.over || game.info_animation_timer){
            if(this.rage.current > 0){
                if(!this.nemesis){
                    this.rage.current -= 0.2;                    
                }
                else{
                    this.rage.current -= 0.1;                    
                }
            }
            else{
                this.rage.current = 0;                
            }

            if(this.nemesis){
                const nemesis_action_params = frame_data[this.nemesis.name][this.nemesis.currentAction];
                if(this.type == "bot"){
                    if(this.nemesis.currentAction.split("_")[0] != "walk"){
                        this.reaction(nemesis_action_params);                
                    }
                    // если идем во время боя, то реакция как на действие stand
                    else{
                        this.reaction(frame_data[this.name]["stand" + this.nemesis.direction]);                
                    }                    
                }
                this.block(nemesis_action_params, my_action_params);
            }
            this.countFrameData(my_action_params);            
        }
        this.draw();
    }
    countFrameData(my_action_params){
        // game.player.rage.current = 100;
        // Если анимаци продолжается, то есть номер кадра менбше разнициы end и start
        var action = frame_data[this.name][this.currentAction];

        if(action && this.currentFrame < frame_data[this.name][this.currentAction].end - frame_data[this.name][this.currentAction].start - 1){
            if(frame_data[this.name][this.currentAction].speed){
                this.currentFrame = Math.round(this.currentFrame
                + frame_data[this.name][this.currentAction].speed);
            }
            else{
                this.currentFrame = Math.round(this.currentFrame + this.frameSpeed);                
            }
            // Если прыжок и нет верхнего удара
            if(this.dy && this.currentAction.split("_")[0] != "kick"
                && this.currentAction.split("_")[2] != "Up"){
                // узнаем номер кадра в прыжке делением текущего значения dy на восьмую часть максимального значения dy.
                // 8 — число кадров в анимации прыжка
                this.currentFrame = Math.ceil( this.dy / (Math.PI / 8) );
            }

            if(!this.stopped && this.x >= 0 && this.x <= canvas.width){
                this.x += this.dx;
                if(this.x < 0){
                    this.x = 0;
                }
                else if(this.x > canvas.width){
                    this.x = canvas.width;
                }                                             
            }

            if(this.type == "player"){
                // console.log(key_down["walk" + this.direction], "walk" + this.direction, this.currentAction)
            }    
        }
        // Если анимация завершилась
        else{
            this.complex = false;
            // Если отжата кнопка,
            // то меняем действие на stand и обнуляем dx, на случай если персонаж шел
            // if(this.type == "player"){
            //     console.log(key_down[this.currentAction.split("_")[0]], this.currentAction.split("_")[0], this.currentAction)
            // }
            if(this.currentAction.split("_")[0] == "walk"){
                var current_action = this.currentAction;
            }
            else{
                var current_action = this.currentAction + this.direction;                
            }

            if(!key_down[current_action] || this.type == "bot"){
                if(this.type == "player"){
                    // console.log("Отжата", current_action, key_down[current_action])
                }                
                if(this.type != "bot" && !arrow_down || this.type == "bot" && !this.crouch ||
                    this.stunCount > 0){ 

                    if(this.type == "bot"){
                        // console.log(this.currentFrame, this.currentAction, frame_data[this.name][this.currentAction].end - frame_data[this.name][this.currentAction].start - 1)                
                    }
                    // Встаем
                    this.doAction('stand' + this.direction);
                    if(this.type != "bot" && this.nemesis && this.nemesis.crouch){
                        this.nemesis.crouch = false;
                    }
                }
                // Если не нажата кнопка вниз
                else{
                    // Продолжаем сидеть
                    this.currentAction = "crouch" + this.direction + "_Down";                 
                }                    
                this.dx = 0; 
            }
            // Иначе просто обнуляем currentFrame кадра и анимация начнется снова
            else{
                if(!my_action_params.no_return
                    && this.currentAction.split("_")[0] != "walk"){
                    key_down[this.currentAction] = false;                   
                    this.doAction('stand' + this.direction);                 
                }
                else if(!my_action_params.once){
                    this.currentFrame = 0;
                    if(!this.stopped && this.x >= 0 && this.x <= canvas.width){
                        this.x += this.dx; // добавляем для плавности перемещение в конце анимации walk
                        if(this.x < 0){
                            this.x = 0;
                        }
                        else if(this.x > canvas.width){
                            this.x = canvas.width;
                        }
                    }                    
                }
            }               
        }
        // условие для прыжка
        if(this.dy){
            // примем максимально значение dy за число пи
            if(this.dy <= Math.PI){
                // косинус менятеся от 1 (при dy = 0) до 0 (при dy = Math.PI/2) и снова до 1 (при dy = Math.PI)
                // Поэтому к середине прыжка скорость замедлится до 0 (5 * 0 = 0)
                this.y -= 50 * Math.cos(this.dy);
                this.dy += Math.PI / 8;
            }
            // прыжок закончился
            if(this.dy > Math.PI){
                this.dy = 0;
                this.dx = 0;
                // key_down["walk" + this.direction] = false;
                if(!game.info_animation_timer){
                    this.y = canvas.height - this.frameHeight / 2;                
                }
                else{
                    this.y = 100;                
                }
                this.doAction('stand' + this.direction);
                this.currentFrame = 0;
            }
        }
        // если прыжка нет, то персонаж всегда внизу экрана, даже если изменили размер окна
        else{
            if(!game.info_animation_timer){
                this.y = canvas.height - this.frameHeight / 2;                
            }
            else{
                this.y = 100;                
            }
        }
    }
    block(nemesis_action_params, my_action_params){
        // Проверка на блок и пересчет здоровья
        const [action_name, action_hor_direct, action_vert_direct] = this.currentAction.split("_");
        const [nemesis_action_name, nemesis_action_hor_direct, nemesis_action_vert_direct] = this.nemesis.currentAction.split("_");        
        const condition = this.nemesis.currentFrame == Math.round((nemesis_action_params.end - nemesis_action_params.start) / 2);
        const start = nemesis_action_params.start;
        const condition2 = "active" in nemesis_action_params
        && start + this.nemesis.currentFrame > nemesis_action_params.active.start
        && start + this.nemesis.currentFrame < nemesis_action_params.active.end;
      
        // if(this.type == "player" && nemesis_action_params.active){
        //     console.log(start + this.nemesis.currentFrame , nemesis_action_params.active.start
        // , nemesis_action_params.active.end, start + this.nemesis.currentFrame > nemesis_action_params.active.start
        // , start + this.nemesis.currentFrame < nemesis_action_params.active.end)
        // }  
        
        if("damage" in nemesis_action_params &&
        (nemesis_action_hor_direct == "Left" && this.nemesis.x > this.x ||
        nemesis_action_hor_direct == "Right" && this.nemesis.x < this.x)
            && (condition || condition2) ){
            let resist = 0;

            // противодействие урону
            const start2 = frame_data[this.name][this.currentAction].start;
            const condition3 = "active" in frame_data[this.name][this.currentAction]
            && start2 + this.currentFrame > frame_data[this.name][this.currentAction].active.start
            && start2 + this.currentFrame < frame_data[this.name][this.currentAction].active.end;

            // if(this.type == "player"){
            //     console.log()            
            // }
            let damage = nemesis_action_params.damage * 3;
            // Чем выше урон от противника, тем выше ярость
            const rage_delta = 10 * damage;
            if(condition3 && "resist" in my_action_params){ // если действие содержит resist
                // проверяем разнонаправленность по горизонтали ("_Left", "_Right")

                if(action_hor_direct != nemesis_action_hor_direct){
                    // проверяем совпадение направления по вертиакали ("Up", "Down", undefined)
                    if(action_vert_direct == nemesis_action_vert_direct){
                        resist = my_action_params.resist;
                        this.nemesis.coolDown = 2;
                    }
                }
                else{
                    this.rage.current += rage_delta;
                }      
                this.stopCount += 25;
            }
            else{
                this.rage.current += rage_delta;
            }

            if(this.rage.current > this.rage.max){
                this.rage.current = this.rage.max;
            }

            if(this.nemesis.rage.current >= this.nemesis.rage.max * 0.9){
                damage *= 10;
                this.nemesis.stunCount = 1;
                if(this.type == "player"){
                    this.nemesis.doAction("punch" + this.nemesis.direction);                    
                }             
                this.nemesis.rage.current = 0;
            }

            this.health.current -= damage - resist;
            if(this.health.current <= 0){
                this.health.current = 0;
                game.over = true;
                if(this.type == "bot"){
                    player_win++; 
                }
                else{
                    bot_win++;                     
                }
                round++;
                game.checkWin();
            }
        }
    }
    draw(){
        const key = frame_data[this.name][this.currentAction];
        if(key){
            const { start, end } = key;
            ctx.drawImage(this.image,
                (start + this.currentFrame) * this.frameWidth, 0,
                this.frameWidth, this.frameHeight,
                this.x - this.frameWidth / 2, this.y - this.frameHeight / 2, this.frameWidth * this.size, this.frameHeight * this.size);            
        }
    }
    // метод объединяет вызов анимации и метода действия (чтобы не вызывать анимацию в каждом действии отдельно)
    doAction(action){
        if(this.type != "bot"){
            if(frame_data[this.name][action]){
                if("cool_down" in frame_data[this.name][action]){                    
                    if(!this.coolDownArray[action]){
                        this.coolDownArray[action] = 0;
                    }
                    if(action == this.currentAction){
                        this.coolDownArray[action]++;                        
                    }
                    else{
                        this.coolDownArray[action] = 0;                        
                    }
                    // console.log(this.coolDownArray[action], action, this.currentAction)
                }                                
            }            
        }
        // frame_data[this.name][action].cool_down - 1 — отсчет от нуля, а ключ объекта от единицы
        if(this.stunCount > 0 || this.coolDown > 0
            || frame_data[this.name][action] 
            && frame_data[this.name][action].cool_down
            && this.coolDownArray[action]
            && this.coolDownArray[action] >= frame_data[this.name][action].cool_down - 1 ){
            
            if(this.coolDownArray[action] >= frame_data[this.name][action].cool_down - 1){
                this.coolDownArray[action] = 0; 
                this.stunCount = 1;               
            }

            // перезаписываем action            
            action = "stand" + this.direction;
        }
        if(!this.dy){ // производим удар, только если мы не в прыжке
            // Сложные действия, состоящие из нескольких, вернут флаг true.
            let complicated_action_flag;
            if(this[action]){
                complicated_action_flag = this[action](action); // вызываем конкретный метод действия или удара
            }
            else{
                console.log("Нет такого действия "  + action + " в объекте frame_data[this.name]")                
            }

            //  Без этого флага будет пытаться названчить в this.currentAction несуществующее действие
            if(frame_data[this.name][action] && !complicated_action_flag){
                this.currentAction = action; // это в том числе идентификатор для анимации                            
            }
        }
        // если в прыжке, то выполняются только верхние удары (все верхние удары называются kick)
        else{
            if(action.split("_")[0] == "kick" && action.split("_")[2] == "Up"){
                this.currentAction = action;
            }
        }
        this.currentFrame = 0;            
    }
    jumpAside_Right(){
        this.doAction("walk_Right");
        this.doAction("jump_Right");
        return true;
    }
    jumpAside_Left(){
        this.doAction("walk_Left");
        this.doAction("jump_Left");
        return true;
    }
    jumpAsidePunch_Right(){
        this.doAction("walk_Right");
        this.doAction("jump_Right");
        let context = this;
        setTimeout(function(){
            context.complex = true;
            context.direction = "_Right"
            context.doAction("kick_Right_Up")
            console.log(context.currentAction, context.direction)
        } , 100);
        return true;              
    }
    jumpAsidePunch_Left(){
        this.doAction("walk_Left");
        this.doAction("jump_Left");
        let context = this;
        setTimeout(function(){
            context.complex = true;
            context.direction = "_Left"
            context.doAction("kick_Left_Up")
        } , 100);
        return true;
    }    
    walkAway_Left(){ 
        if(!this.crouch){
            this.doAction("walk_Right");
            return true;
        }       
    }
    walkAway_Right(){   
        if(!this.crouch){
            this.doAction("walk_Left");
            return true;
        }
    }    
    walk_Left(){
        if(!this.stopped){
            this.dx = -this.speed;
        }
        this.direction = '_Left';        
    }
    walk_Right(){
        if(!this.stopped){
            this.dx = this.speed;
        }             
        this.direction = '_Right';
    }
    punch_Right(){

    }
    punch_Left(){

    }
    punch_Right_Down(){

    }
    punch_Left_Down(){

    }    
    block_Right(){

    }
    block_Left(){

    }
    block_Right_Up(){

    }
    block_Left_Up(){

    }
    block_Right_Down(){

    }
    block_Left_Down(action){
        // if(this.currentAction != "crouch_Left"){
        //     this.doAction("crouch_Left");
        //     // let context = this;
        //     // setTimeout(function(){
        //     //     // context.complex = true;
        //     //     context.doAction("punch_Left")
        //     // } , 100);          
        // }
        // // else{
        // //     this.currentAction = action;
        // // }
        // return true;
    }
    jump_Right(){
        this.dy = 0.1;
    }
    jump_Left(){
        this.dy = 0.1;
    }
    crouch_Right_Down(){
        if(this.type == "bot"){
            this.crouch = true;
        }
    }
    crouch_Left_Down(){
        if(this.type == "bot"){
            this.crouch = true;
        }
    }
    crouch_Right_Up(){
        if(this.type == "bot"){
            this.crouch = false;
        }        
    }
    crouch_Left_Up(){
        if(this.type == "bot"){
            this.crouch = false;
        } 
    }    
    kick_Right_Up(){

    }
    kick_Left_Up(){

    }
    stand_Left(action){
        if(this.currentAction == "crouch_Left_Down"){
            this.currentAction = "crouch_Left_Up";           
        }
        else{
            this.currentAction = action;
        }
        return true;
    }
    stand_Right(action){
        if(this.currentAction == "crouch_Right_Down"){
            this.currentAction = "crouch_Right_Up";           
        }
        else{
            this.currentAction = action;
        }
        return true;
    }
    test_Left(){
        console.log("Left_________________________");
    }
    test_Right(){
        console.log("Right_________________________");
    }    
}