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

const mapAngles: Record<number, number> = {
	0: 2,
	45: 3,
	90: 4,
	135: 5,
	180: 6,
	225: 7,
	270: 0,
	315: 1,
};

export class Knife implements Weapon {
	private readonly canvas: HTMLCanvasElement;
	private hitInterval = new Interval(1500);
	private projectileInterval = new Interval(200);

	private speed = 0.1;
	private power = 2;
	private projectiles = 1;
	private damageArea = 8;
	private _level = 1;

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

	get key() {
		return 'knife';
	}

	constructor() {
		const image = resources.getImage('dungeon');

		this.canvas = document.createElement('canvas');
		this.canvas.width = 16 * 8;
		this.canvas.height = 16;

		const ctx = this.canvas.getContext('2d') as CanvasRenderingContext2D;

		const y = 0;
		const width = 6;
		const height = 14;
		const halfWidth = width / 2;
		const halfHeight = height / 2;
		const r45 = (45 * Math.PI) / 180;
		for (let i = 0; i < 8; i++) {
			const x = 16 * i;
			const angleInRadians = r45 * i;

			ctx.translate(x + halfWidth, y + halfHeight);
			ctx.rotate(angleInRadians);

			ctx.drawImage(
				image,
				293,
				18,
				width,
				height,
				-halfWidth,
				-halfHeight,
				width,
				height,
			);

			ctx.rotate(-angleInRadians);
			ctx.translate(-x - width / 2, -y - height / 2);
		}
	}

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

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

		this._projectiles.forEach((projectile) => {
			addV(
				projectile.position,
				multiply(copy(projectile.direction), dt * this.speed),
			);
		});
	}

	private addProjectile(position: Vector, direction: Vector) {
		this._projectiles.push({
			position: copy(position),
			direction: copy(direction),
			angle: (Math.round((angle(direction) * 180) / Math.PI) + 360) % 360,
			alive: true,
		});
	}

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

		this._projectiles.forEach((projectile) => {
			const offset = mapAngles[projectile.angle];
			if (offset === undefined) return;

			ctx.drawImage(
				this.canvas,
				offset * 16 - 4,
				0,
				14,
				14,
				Math.round(projectile.position[0] - 7),
				Math.round(projectile.position[1] - 7),
				14,
				14,
			);

			// ctx.fillStyle = 'red';
			// ctx.beginPath();
			// ctx.arc(
			// 	projectile.position[0],
			// 	projectile.position[1],
			// 	1,
			// 	0,
			// 	2 * Math.PI,
			// 	false,
			// );
			// ctx.fill();
		});
	}

	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 Knife;
