const assets=require('assets');
const config=require('config');
const {tiles: T}=require('tiles');

// declare our tiles
let snake,
	wall, hole,
	fire, flammable,
	fruit, superFruit, decayFruit,
	portalA, portalB, portalC, portalD,
	key, door,
	switchTile, spikes;

// load our tiles
assets.onReady(() => {
	wall=assets.get('wall');
	hole=assets.get('hole');
	fire=assets.get('fire');
	flammable=assets.get('flammable');
	superFruit=assets.get('superFruit');
	decayFruit=assets.get('decayFruit');
	portalA=assets.get('portalA');
	portalB=assets.get('portalB');
	portalC=assets.get('portalC');
	portalD=assets.get('portalD');
	key=assets.get('key');
	door=assets.get('door');
	switchTile=assets.get('switch');
	spikes=assets.get('spikes');
	snake=assets.get('snake');
	fruit=assets.get('fruit');
});

const draw=(game, canvas=game.canvas, ctx=canvas.getContext('2d')) => {
	// clear the canvas, because it's easier than having to deal with everything
	ctx.clearRect(0, 0, canvas.width, canvas.height);

	// get the cell size and offset
	const cellSize=Math.min(
		canvas.width/game.dimensions[0],
		canvas.height/game.dimensions[1]
	);
	const offsetX=(canvas.width-cellSize*game.dimensions[0])/2;
	const offsetY=(canvas.height-cellSize*game.dimensions[1])/2;

	// tile draw functions
	const putTile=(x, y, tile) => ctx.drawImage(
		tile,
		offsetX+cellSize*x,
		offsetY+cellSize*y,
		cellSize,
		cellSize
	);
	const putTileAnim=(x, y, tile) => putTile(x, y, tile[
		Math.floor(Date.now()/1000*60+x+y)%tile.length
	]);
	const putTileAnimPercent=(x, y, tile, percent) => putTile(x, y, tile[
		Math.min(Math.round(percent*tile.length), tile.length-1)
	]);

	// adjascence check
	const checkAdj=(x, y) => {
		let adj={};
		adj.u=game.world[x][y-1];
		adj.d=game.world[x][y+1];
		adj.l=(game.world[x-1] || [])[y];
		adj.r=(game.world[x+1] || [])[y];
		adj.ul=(game.world[x-1] || [])[y-1];
		adj.ur=(game.world[x+1] || [])[y-1];
		adj.dl=(game.world[x-1] || [])[y+1];
		adj.dr=(game.world[x+1] || [])[y+1];
		return adj;
	};

	// draw a grid/checkerboard if requested
	if(config.getS('appearance.grid')=='grid') {
		ctx.strokeStyle='rgba(0, 0, 0, 50%)';
		ctx.lineCap='square';
		ctx.lineWidth=1;
		ctx.beginPath();
		for(let x=1; x<game.dimensions[0]; x++) {
			ctx.moveTo(offsetX+x*cellSize, offsetY);
			ctx.lineTo(offsetX+x*cellSize, canvas.height-offsetY);
		}
		for(let y=1; y<game.dimensions[1]; y++) {
			ctx.moveTo(offsetX, offsetY+y*cellSize);
			ctx.lineTo(canvas.width-offsetX, offsetY+y*cellSize);
		}
		ctx.stroke();
	} else if(config.getS('appearance.grid')=='checkerboard') {
		ctx.fillStyle='rgba(0, 0, 0, 10%)';
		for(let x=0; x<game.dimensions[0]; x++) {
			for(let y=(x+1)%2; y<game.dimensions[1]; y+=2) {
				ctx.fillRect(offsetX+x*cellSize, offsetY+y*cellSize, cellSize, cellSize);
			}
		}
	}

	// draw our tiles
	for(let x=0; x<game.dimensions[0]; x++) {
		for(let y=0; y<game.dimensions[1]; y++) {
			switch(game.world[x][y]) {
				case T.WALL:
					putTile(x, y, wall);
					break;

				case T.FIRE:
					putTileAnim(x, y, fire);
					break;

				case T.HOLE:
				case T.HOLE_S: {
					putTile(x, y, hole.base);
					let adj=checkAdj(x, y);
					Object
						.keys(adj)
						.filter(k => adj[k]==T.HOLE || adj[k]==T.HOLE_S)
						.forEach(k => putTile(x, y, hole[k]));
				} break;

				case T.FLAMMABLE:
				case T.FLAMMABLE_S:
					putTile(x, y, flammable);
					break;

				case T.SUPER_FOOD:
					putTileAnim(x, y, superFruit);
					break;

				case T.PORTAL_A:
				case T.PORTAL_A_S:
					putTileAnim(x, y, portalA);
					break;
				case T.PORTAL_B:
				case T.PORTAL_B_S:
					putTileAnim(x, y, portalB);
					break;
				case T.PORTAL_C:
				case T.PORTAL_C_S:
					putTileAnim(x, y, portalC);
					break;
				case T.PORTAL_D:
				case T.PORTAL_D_S:
					putTileAnim(x, y, portalD);
					break;

				case T.KEY:
					putTile(x, y, key);
					break;
				case T.DOOR:
					putTile(x, y, door);
					break;

				case T.SWITCH_ON:
				case T.SWITCH_ON_S:
					putTile(x, y, switchTile.on);
					break;
				case T.SWITCH_OFF:
				case T.SWITCH_OFF_S:
					putTile(x, y, switchTile.off);
					break;

				case T.SPIKES_ON:
					putTile(x, y, spikes.on);
					break;
				case T.SPIKES_OFF:
				case T.SPIKES_OFF_S:
					putTile(x, y, spikes.off);
					break;
			}
		}
	}

	// draw our decaying fruits (they have more information than just XY, so they need to be drawn here
	game.decayFood.forEach(([x, y, birth]) =>
		putTileAnimPercent(x, y, decayFruit, (game.playTime-birth)/2000)
	);

	// draw the lines between portals
	if(Object.keys(game.portals).length) {
		ctx.strokeStyle='rgba(128, 128, 128, 20%)';
		ctx.lineCap='round';
		ctx.lineWidth=cellSize*.15;
		const drawTunnel=([xa, ya], [xb, yb]) => {
			const angle=(Math.floor(Date.now()/10)%360)*(Math.PI/180);
			for(let i=0; i<=1; i++) {
				const dx=cellSize/3*Math.cos(angle+i*Math.PI);
				const dy=cellSize/3*Math.sin(angle+i*Math.PI);
				ctx.beginPath();
				ctx.moveTo(
					offsetX+cellSize*(xa+1/2)+dx,
					offsetY+cellSize*(ya+1/2)+dy
				);
				ctx.lineTo(
					offsetX+cellSize*(xb+1/2)+dx,
					offsetY+cellSize*(yb+1/2)+dy
				);
				ctx.stroke();
			}
		};
		if(game.portals.a && game.portals.b) drawTunnel(game.portals.a, game.portals.b);
		if(game.portals.c && game.portals.d) drawTunnel(game.portals.c, game.portals.d);
	}

	// draw our snake (it gets drawn completely differently, so here it goes)
	{
		ctx.fillStyle=snake.color;
		ctx.strokeStyle=snake.color;
		ctx.lineCap=snake.cap;
		ctx.lineJoin=snake.join;
		ctx.lineWidth=cellSize*snake.tailSize;

		ctx.beginPath();
		ctx.ellipse(
			offsetX+cellSize*(game.snake[0][0]+1/2),
			offsetY+cellSize*(game.snake[0][1]+1/2),
			cellSize/2*snake.headSize,
			cellSize/2*snake.headSize,
			0,
			0,
			Math.PI*2
		);
		ctx.fill();

		ctx.beginPath();
		game.snake.forEach(([x, y], i, a) => {
			ctx.lineTo(
				offsetX+cellSize*(x+1/2),
				offsetY+cellSize*(y+1/2)
			);
			if(i!=0 && Math.hypot(x-a[i-1][0], y-a[i-1][1])>1) {
				ctx.lineWidth=cellSize*snake.tailWrapSize;
			} else {
				ctx.lineWidth=cellSize*snake.tailSize;
			}
			ctx.stroke();
			ctx.beginPath()
			ctx.moveTo(
				offsetX+cellSize*(x+1/2),
				offsetY+cellSize*(y+1/2)
			);
		});
		ctx.stroke();
	}

	// our fruit has a nice animation to it between .8 and 1.2 scale
	{
		const ms=Date.now();
		const fruitScale=Math.sin(ms/400*Math.PI)*.2+1
		game.fruits.forEach(([x, y]) => {
			ctx.drawImage(
				fruit,
				offsetX+cellSize*x+(1-fruitScale)*cellSize/2,
				offsetY+cellSize*y+(1-fruitScale)*cellSize/2,
				cellSize*fruitScale,
				cellSize*fruitScale
			);
		});
	}

	// show the timer
	if(game.rules.winCondition=='time') {
		if(config.getS('appearance.timer')=='border' || config.getS('appearance.timer')=='both') {
			let remaining=(game.rules.gameDuration-game.playTime)/game.rules.gameDuration;
			const w=game.dimensions[0]*cellSize;
			const h=game.dimensions[1]*cellSize;
			const p=w*2+h*2;

			const wp=w/p;
			const hp=h/p;

			const pdst=(st, ed, frac) =>
				(ed-st)*frac+st;

			ctx.strokeStyle='#930a16';
			ctx.lineJoin='miter';
			ctx.lineCap='round';
			ctx.lineWidth=5;
			ctx.beginPath();
			ctx.moveTo(canvas.width/2, offsetY+2);

			let sp=Math.min(wp/2, remaining);
			remaining-=sp;
			ctx.lineTo(pdst(canvas.width/2, w+offsetX-2, sp/wp*2), offsetY+2);
			if(remaining) {
				sp=Math.min(hp, remaining);
				remaining-=sp;
				ctx.lineTo(w+offsetX-2, pdst(offsetY+2, offsetY+h-2, sp/hp));
			}
			if(remaining) {
				sp=Math.min(wp, remaining);
				remaining-=sp;
				ctx.lineTo(pdst(w+offsetX-2, offsetX+2, sp/wp), offsetY+h-2);
			}
			if(remaining) {
				sp=Math.min(hp, remaining);
				remaining-=sp;
				ctx.lineTo(offsetX+2, pdst(offsetY+h-2, offsetY+2, sp/hp));
			}
			if(remaining) {
				ctx.lineTo(pdst(offsetX+2, canvas.width/2, remaining/wp*2), offsetY+2);
			}
			ctx.stroke();
		}
		if(config.getS('appearance.timer')=='number' || config.getS('appearance.timer')=='both') {
			let remaining=''+Math.ceil((game.rules.gameDuration-game.playTime)/1000);
			while(remaining.length<(''+game.rules.gameDuration/1000).length) remaining='0'+remaining;

			ctx.fillStyle='#930a16';
			ctx.textAlign='center';
			ctx.textBaseline='middle';
			ctx.font='4rem "Fira Code"';
			ctx.fillText(remaining, canvas.width/2, canvas.height/2);
		}
	}

	// draw the border around our game area
	{
		ctx.fillStyle='black';
		ctx.fillRect(0, 0, canvas.width, offsetY);
		ctx.fillRect(0, 0, offsetX, canvas.height);
		ctx.fillRect(offsetX+cellSize*game.dimensions[0], 0, offsetX, canvas.height);
		ctx.fillRect(0, offsetY+cellSize*game.dimensions[1], canvas.width, offsetY);
	}
};

return module.exports={
	draw
};
