class Robot {
    constructor(height, width, x, y, scene, name = 'enemy', speed = SPEED_BEGIN, speedReload = SPEED_RELOAD_BEGIN, range = RANGE_BEGIN, damage = DAMAGE_BEGIN, lNode = []) {
        this.speedBonus = 1;
        this.attackBonus = 1;
        this.name = name;
        this.height = height;
        this.width = width;
        this.x = x;
        this.y = y;
        this.life = new HealthBar(scene, selectWord("LIFE", "VIE"), this.width * 2, this.width / 3, this.x, this.y - this.width, LIFE, 0x008000);
        this.shield = new HealthBar(scene, selectWord("SHIELD", "BOUCLIER"), this.width * 2, this.width / 3, this.x, this.y - this.width * 1.5, SHIELD, 0x0000FF);

        this.canAttack = true;
        this.missile = new Missile(scene, 'bullet', this.width / 5, this.width / 4);
        scene.add.existing(this.missile);

        this.addScene(scene);

        this.lNode = lNode;

        this.setSpeed(speed);
        this.setSpeedReload(speedReload);
        this.setRange(range);
        this.setDamage(damage);

        this.setX(this.x);
        this.setY(this.y);

        this.team = undefined;
    }


    addScene(scene) {
        this.scene = scene;
        if (this.name === 'enemy') {
            this.circle = this.scene.add.image(this.x, this.y, 'enemy').setOrigin(0.5, 0.5).setInteractive();
        } else {
            this.circle = this.scene.add.image(this.x, this.y, 'myBot').setOrigin(0.5, 0.5).setInteractive();
        }
        this.circle.displayWidth = this.width;
        this.circle.displayHeight = this.height;
        this.circle.on('pointerdown', () => this.click());
    }

    click() {
        if (this.circleRange === undefined) {
            this.drawRange();
        } else {
            this.eraseRange();
        }

        this.doEvent();
    }

    addEvent(eventClick, contextClick, value) {
        this.eventClick = eventClick;
        this.contextClick = contextClick;
        this.valueClick = value;
    }

    doEvent() {
        if (this.eventClick !== undefined && this.contextClick !== undefined) {
            this.eventClick.call(this.contextClick, this, this.valueClick);
        }
    }

    addShield(shield) {
        this.shield.increase(shield);
    }

    setX(x) {
        this.x = x;
        this.life.setX(this.x);
        this.shield.setX(this.x);
        this.circle.setX(this.x);
        this.drawCircleRange();
    }

    setY(y) {
        this.y = y;
        let yLife = this.y - this.width;
        let yShield = this.y - this.width * 1.5;
        if (yLife < 0) {
            yShield = this.y + this.width - this.shield.height;
            yLife = this.y + this.width * 1.5 - this.shield.height;
        } else {
            if (yShield < 0) {
                yShield = yLife;
                yLife = this.y + this.width - this.shield.height;
            }
        }
        this.life.setY(yLife);
        this.shield.setY(yShield);
        this.circle.setY(this.y);
        this.drawCircleRange();
    }

    setTint(color) {
        this.circle.setTint(color);
    }

    clearTint() {
        this.circle.clearTint();
    }

    setTarget(target) {
        this.target = target;
    }

    updateTarget() {
        if (this.verifyTarget())
            this.setTargetPos(this.target.x, this.target.y);
    }

    setTargetPos(x, y) {
    }

    setDamage(damage = this.damage) {
        this.damage = damage + DAMAGE_BASE;
    }

    setRange(range = this.range) {
        this.range = range + RANGE_BASE;
        this.drawCircleRange();
    }

    setSpeed(speed = this.speed) {
        this.speed = speed + SPEED_BASE;
    }

    setSpeedReload(speedReload = this.speedReload) {
        this.speedReload = speedReload + SPEED_RELOAD_BASE;
    }

    setAttackBonus(amount) {
        this.attackBonus = amount;
    }

    increaseSpeedBonus(amount) {
        this.speedBonus += amount;
    }

    decreaseSpeedBonus(amount) {
        this.speedBonus -= amount;
    }

    advanceToTarget() {
        if (this.verifyTarget()) {
            this.advanceTo(this.target);
        }
        return false;
    }

    advanceTo(target) {
        if (target.x !== this.x || target.y !== this.y) {
            let x = false;
            let y = false;
            let velocity = this.getVelocity(target);
            let newX = velocity[0] + this.x;
            let newY = velocity[1] + this.y;
            if ((velocity[0] >= 0 && newX >= target.x) || (velocity[0] <= 0 && newX <= target.x)) {
                this.setX(target.x);
                x = true;
            } else
                this.setX(this.x + velocity[0]);

            if ((velocity[1] >= 0 && newY >= target.y) || (velocity[1] <= 0 && newY <= target.y)) {
                this.setY(target.y);
                y = true;
            } else
                this.setY(this.y + velocity[1]);
            return !(x && y);
        }
        return false;
    }

    fleeFromTarget() {
        if (this.verifyTarget()) {
            return this.fleeFrom(this.target)
        }
        return false;
    }

    fleeFrom(target) {
        if (this.target.x !== this.x || this.target.y !== this.y) {
            let velocity = this.getVelocity(target, true);
            if (velocity[0] >= 0 && this.x - this.width / 2 <= 0) {
                this.setX(this.width / 2);
            } else if (velocity[0] <= 0 && this.x + this.width / 2 >= WIDTH_MAP)
                this.setX(WIDTH_MAP - this.width / 2);
            else
                this.setX(this.x - velocity[0]);

            if (velocity[1] >= 0 && this.y - this.width / 2 <= 0)
                this.setY(this.height / 2);
            else if (velocity[1] <= 0 && this.y + this.width / 2 >= WIDTH_MAP)
                this.setY(WIDTH_MAP - this.height / 2);
            else
                this.setY(this.y - velocity[1]);
            return true;
        }
        return false;
    }

    getVelocity(target, calcul = false) {
        let velocity = [];
        let diffX = target.x - this.x;
        let diffY = target.y - this.y;
        if (diffX === 0 && diffY === 0) {

        }
        let hypot = Math.hypot(diffX, diffY);
        velocity[0] = diffX / hypot * SPEED * this.speed * this.speedBonus * SPEED_GAME; // Velocity X
        velocity[1] = diffY / hypot * SPEED * this.speed * this.speedBonus * SPEED_GAME; // Velocity Y
        if (calcul) {
            if (this.x + this.width / 2 + velocity[0] > WIDTH_MAP || this.x - this.width / 2 - velocity[0] < 0) {
                velocity[1] += velocity[0] * Math.sign(velocity[1]);
                velocity[0] = 0;
            } else {
                if (this.y + this.width / 2 - velocity[1] > WIDTH_MAP || this.y - this.width / 2 + velocity[1] < 0) {
                    velocity[0] += velocity[1] * Math.sign(-velocity[0]);
                    velocity[1] = 0;
                }
            }
        }

        return velocity;
    }


    attackTarget(percentBonus = 0) {
        if (this.verifyTarget()) {
            if (this.canAttack)
                this.attack(this.target, percentBonus);
            return true;
        }
        return false;
    }

    verifyTarget() {
        if (this.haveTarget()) {
            if (!this.target.isAlive()) {
                this.setTarget(null);
                return false;
            }
            return true;
        }
        return false;
    }

    attack(target, percentBonus) {
        this.canAttack = false;

        this.missile.setPosition(this.x, this.y).setVisible(true);

        this.missile.setRotation(Math.atan2(this.y - this.target.y, this.x - this.target.x) - 3.14 / 2);

        this.scene.sound.play('shot', {rate: SPEED_GAME});

        let duration = this.calcDistance(this.target) * WIDTH_MAP / 1000;

        this.scene.tweens.add({
            targets: this.missile,
            x: target.x,
            y: target.y,
            ease: 'Linear',
            duration: duration,
            onComplete: () => this.finishAttack(target, percentBonus)
        });

        this.scene.time.addEvent({
            delay: SPEED_RELOAD / this.speedReload,
            callback: this.reload,
            callbackScope: this
        });
    }

    finishAttack(target, percentBonus) {
        if (target.beAttack(this.damage * this.attackBonus * DAMAGE * percentBonus, this.team)) {
            this.setTarget(null);
        }
        this.missile.setVisible(false);
        if (this.attackBonus !== 1) {
            this.setAttackBonus(1);
        }
    }

    reload() {
        this.canAttack = true;
    }

    beAttack(damage, team) {
        let diff = this.shield.decrease(damage);

        let style = {font: HEIGHT_DAMAGE.toString() + 'px stencil', fill: "#ffff00"};
        let text = this.scene.add.text(this.x, this.y, damage.toString(), style).setOrigin(0, 1);

        this.scene.tweens.add({
            targets: text,
            x: this.x + 30,
            y: this.y - 50,
            alpha: 0,
            duration: DURATION_DAMAGE,
            ease: 'Sine.easeOut',
            onComplete: () => text.destroy()
        })

        this.scene.sound.play('hit', {rate: SPEED_GAME});
        console.log('HIT');

        if (diff > 0) {
            console.log("Shield Broken");
            this.life.decrease(diff);
        }
        this.addScore(team)
        return this.die();
    }

    addScore(team) {
        if (team !== undefined) {
            team.addScore(SCORE_HIT);
            if (this.life.value === 0) {
                team.addScore(SCORE_KILL);
            }
        }
    }

    isTargetInRange(percentRange = 1) {
        if (this.haveTarget()) {
            return this.calcDistance(this.target) <= this.range * RANGE * percentRange;
        }
        return false;
    }

    calcDistance(robot) {
        return Math.hypot(robot.x - this.x, robot.y - this.y);
    }

    isAlive() {
        return this.life.value > 0;
    }

    die() {
        if (this.life.value === 0) {
            if (this.circleRange !== undefined)
                this.circleRange.destroy();
            this.circle.destroy();
            this.shield.destroy();
            this.life.destroy();
            return true;
        }
        return false;
    }

    haveTarget() {
        return this.target != null;
    }

    read() {
        this.verifyTarget();
        for (let i = 0; i < this.lNode.length; i++) {
            if (this.lNode[i].do(this)) {
                break;
            }
        }
    }

    addNode(node) {
        this.lNode.push(node);
    }

    drawRange() {
        this.circleRange = this.scene.add.graphics();

        this.drawCircleRange();
    }

    eraseRange() {
        if (this.circleRange !== undefined) {
            this.circleRange.clear();
            this.circleRange = undefined;
        }
    }

    drawCircleRange() {
        if (this.circleRange !== undefined) {

            this.circleRange.clear();

            let color = COLOR_GREEN;
            let thickness = WIDTH_LINE / 2;
            let alpha = 1 / 3;
            this.circleRange.lineStyle(thickness, color, alpha);
            let radius = this.range * RANGE;
            this.circleRange.strokeCircle(this.x, this.y, radius);

            color = COLOR_ORANGE;
            alpha = 2 / 3;
            this.circleRange.lineStyle(thickness, color, alpha);
            radius = this.range * RANGE * 2 / 3;
            this.circleRange.strokeCircle(this.x, this.y, radius);

            color = COLOR_RED;
            alpha = 1;
            this.circleRange.lineStyle(thickness, color, alpha);
            radius = this.range * RANGE / 3;
            this.circleRange.strokeCircle(this.x, this.y, radius);
        }
    }


    cleanNodes() {
        this.lNode = [];
    }

    setNodes(lNode) {
        this.cleanNodes();
        lNode.forEach(node => this.addNode(node));
    }

    setVisible(boolean) {
        this.circle.setVisible(boolean);
        this.life.setVisible(boolean);
        this.shield.setVisible(boolean);
        if (this.circleRange !== undefined) {
            this.circleRange.setVisible(boolean);
        }
    }

    getTreeJson() {
        let json = '{' + toJson("type", "waria");
        json += '"lNode":[';
        this.lNode.forEach(node => json += node.getTreeJson() + ',');
        json = endLineJson(json);
        json += ']}';
        return json;
    }

    copy(robot) {
        robot.lNode = this.lNode;
        robot.damage = this.damage;
        robot.speedReload = this.speedReload;
        robot.speed = this.speed;
        robot.range = this.range;
        if (this.circleRange !== undefined) {
            robot.drawRange();
        } else {
            robot.eraseRange();
        }
    }
}
