import { UpdateOptions, Weapon } from './weapon';
import Interval from '../interval';
import {
	addV,
	copy,
	distance,
	multiply,
	normalize,
	subtractV,
	length,
	Vector,
} from '../vector';
import Unit from '../unit';
import resources from '../resources';

export class Flask implements Weapon {
	private hitInterval = new Interval(2500);
	private projectileInterval = new Interval(300);
	private speed = 0.06;
	private power = 1;
	private projectiles = 1;
	private damageArea = 4;
	private _level = 1;

	private _currentColor = 0;
	private _projectilesLeft = 0;
	private _projectiles: Array<{
		position: Vector;
		direction: Vector;
		angle: number;
		alive: boolean;
		color: number;
	}> = [];

	get key() {
		return 'flask';
	}

	constructor() {}

	update(dt: number, options: UpdateOptions) {
		if (this.hitInterval.next(dt)) {
			this.addProjectile(options.position, options.enemies);
			this._projectilesLeft = this.projectiles - 1;
		}

		if (this._projectilesLeft > 0 && this.projectileInterval.next(dt)) {
			this.addProjectile(options.position, options.enemies);
			this._projectilesLeft--;
		}

		this._projectiles.forEach((projectile) => {
			projectile.angle += dt / 200;

			addV(
				projectile.position,
				multiply(copy(projectile.direction), dt * this.speed),
			);
		});
	}

	private addProjectile(position: Vector, enemies: Unit[]) {
		this._currentColor = (this._currentColor + 1) % 4;

		const nearest = enemies.reduce<Vector | null>((acc, enemy) => {
			const dir = subtractV(copy(enemy.position), position);
			if (acc === null || length(dir) < length(acc)) return dir;
			return acc;
		}, null);

		if (!nearest) return;

		this._projectiles.push({
			position: copy(position),
			direction: normalize(nearest),
			angle: 0,
			alive: true,
			color: this._currentColor,
		});
	}

	draw(ctx: CanvasRenderingContext2D) {
		// ctx.drawImage(this.canvas, 0, 0);

		this._projectiles.forEach((projectile) => {
			ctx.save();
			ctx.translate(
				Math.round(projectile.position[0]),
				Math.round(projectile.position[1]),
			);

			ctx.rotate(projectile.angle);

			ctx.drawImage(
				resources.getImage('dungeon'),
				288 + projectile.color * 16,
				240,
				16,
				16,
				-8,
				-10,
				16,
				16,
			);

			ctx.restore();
		});
	}

	filterProjectiles(left: number, top: number, right: number, bottom: number) {
		this._projectiles = this._projectiles.filter((projectile) => {
			return (
				projectile.alive &&
				projectile.position[0] > left &&
				projectile.position[1] > top &&
				projectile.position[0] < right &&
				projectile.position[1] < bottom
			);
		});
	}

	checkHit(enemy: Unit) {
		this._projectiles.forEach((projectile) => {
			if (
				projectile.alive &&
				distance(projectile.position, enemy.position) < this.damageArea
			) {
				enemy.hit(this.power);
				projectile.alive = false;
			}
		});
	}

	upgrade() {
		this._level++;

		if (this._level % 2 === 0) {
			this.projectiles++;
		}

		if (this._level % 3 === 0) {
			this.hitInterval.decrease(100);
		}

		if (this._level % 4 === 0) {
			this.power++;
		}

		if (this._level % 5 === 0) {
			this.speed -= 100;
		}
	}
}

export default Flask;
