import { EEnemySize, EProjectileEffectType, GdEnemy, GdProjectileEffect, GdRoot, GdWave } from "../../GameData/index.js";
import { Hex, Vector2 } from "../../Util/index.js";
import { SimLevel } from "../index.js";

export class SimEnemy {
    private _index: number;
    private _routeIdx: number;
    private _startHex: Hex;
    private _endHex: Hex;
    private _path: number[];
    private _position: Vector2;
    private _direction: Vector2;
    private _currentPathIndex: number;
    private _currentPathStep: number;
    private _currentPathPosition: Vector2;
    private _dead: boolean = false;
    private _simLevel: SimLevel;
    private _gdEnemy: GdEnemy;
    private _hitPonts: number;
    private _size: EEnemySize;
    private _speed: number;
    private _gain: number;
    private _gdRoot: GdRoot;

    constructor(gdRoot: GdRoot, wave: GdWave, routeIdx: number, level: SimLevel) {
        const gdLevel = level.gdLevel;
        const route = gdLevel.enemyRoutes[routeIdx];

        this._gdRoot = gdRoot;
        this._index = wave.enemy;
        this._simLevel = level;
        this._hitPonts = wave.hitpoints;
        this._size = wave.size;
        this._gain = wave.gain;
        this._startHex = gdLevel.enemySpawns[route[0]];
        this._endHex = gdLevel.enemyTargets[route[1]];
        this._gdEnemy = this._gdRoot.enemies[this._index];
        this._currentPathIndex = 0;
        this._currentPathStep = level.currentStep;
        this._dead = false;
        this._routeIdx = routeIdx;
        this._path = level.simCells[level.getCellIndex(this._startHex)].pathsToTarget[routeIdx];
        this._position = level.simCells[this._path[0]].hex.toWorld();
        this._direction = level.simCells[this._path[1]].hex.toWorld().subtract(this._position).normalized();
        this._currentPathPosition = this._position;

        this._speed = this._gdEnemy.speed;
        switch (wave.size) {
            case EEnemySize.Tiny:
                this._speed *= 2;
                break;
            case EEnemySize.Huge:
                this._speed *= 0.5;
                break;
        }
    }

    public get path(): number[] {
        return this._path;
    }

    public set path(value: number[]) {
        this._path = value;
    }

    public get position(): Vector2 {
        return this._position;
    }

    public set position(value: Vector2) {
        this._position = value;
    }

    public get direction(): Vector2 {
        return this._direction;
    }

    public get endHex(): Hex {
        return this._endHex;
    }

    public get currentPathIndex(): number {
        return this._currentPathIndex;
    }

    public set currentPathIndex(value: number) {
        this._currentPathIndex = value;
    }

    public get currentPathStep(): number {
        return this._currentPathStep;
    }

    public set currentPathStep(value: number) {
        this._currentPathStep = value;
    }

    public get currentPathPosition(): Vector2 {
        return this._currentPathPosition;
    }

    public get dead(): boolean {
        return this._dead;
    }

    public set dead(value: boolean) {
        this._dead = value;
    }

    public get speed(): number {
        return this._speed;
    }

    public get size(): EEnemySize {
        return this._size;
    }

    public get index(): number {
        return this._index;
    }

    public suffer = (effect: GdProjectileEffect) => {
        switch (effect.type) {
            case EProjectileEffectType.Damage:
                {
                    this._hitPonts -= effect.amount;
                    if (this._hitPonts <= 0) {
                        this._simLevel.currency += this._gain;
                        this._dead = true;
                    }
                    break;
                }
        }
    }

    public onPathUpdated = () => {
        const myPos = this._position;
        this._currentPathPosition = myPos;

        if (this._path == null) {
            return;
        }

        const current = this._path[this._currentPathIndex];
        const next = this._path[this._currentPathIndex + 1];
        if (!next) {
            return;
        }

        const cells = this._simLevel.simCells;
        const pos1 = cells[current].hex.toWorld();
        const pos2 = cells[next].hex.toWorld();
        const myDir = pos2.subtract(myPos);
        const myLen = myDir.magnitude();
        const hexDir = pos2.subtract(pos1);
        const hexLen = hexDir.magnitude();
        if (myLen > hexLen) {
            this._path.unshift(this._path[0]);
        }

        this._direction = myDir.multiplyScalar(1 / myLen);
    }
}
