package com.danitheskunk.skunkworks.backends.gl;

import com.danitheskunk.skunkworks.Recti;
import com.danitheskunk.skunkworks.Vec2i;
import com.danitheskunk.skunkworks.gfx.*;

import static org.lwjgl.opengl.GL46.*;

class RenderContext extends BaseRenderContext implements IRenderContext {
	private final int texCoordIndex;
	private final int texOffsetIndex;
	private final int texSizeIndex;
	private final int tintIndex;

	public RenderContext(
		Vec2i size, int texCoordIndex, int texOffsetIndex,
		int texSizeIndex, int tintIndex
	) {
		super(size);
		this.texCoordIndex = texCoordIndex;
		this.texOffsetIndex = texOffsetIndex;
		this.texSizeIndex = texSizeIndex;
		this.tintIndex = tintIndex;
	}

	@Override
	public void drawNineSlice(NineSlice slice, Recti rect) {
		var centerWidth = Math.max(0,
			rect.getWidth() -
				slice.getLeft().getSize().getX() -
				slice.getRight().getSize().getX()
		);
		var centerHeight = Math.max(0,
			rect.getHeight() -
				slice.getTop().getSize().getY() -
				slice.getBottom().getSize().getY()
		);
		var pos = rect.getPos();

		drawTexture(pos, slice.getTopLeft());
		drawTexture(new Vec2i(pos.getX() +
			slice.getLeft().getWidth() +
			centerWidth,
			pos.getY()
		), slice.getTopRight());
		drawTexture(
			new Vec2i(pos.getX(),
				pos.getY() + slice.getTop().getHeight() + centerHeight
			),
			slice.getBottomLeft()
		);
		drawTexture(Vec2i.add(pos,
			slice.getTopLeft().getSize(),
			new Vec2i(centerWidth, centerHeight)
		), slice.getBottomRight());

		drawTextureRectangle(new Recti(Vec2i.add(pos,
			slice.getTopLeft().getSize()
		),
			new Vec2i(centerWidth, centerHeight)
		), slice.getCenter(), true);

		//top
		drawTextureRectangle(new Recti(pos.getX() + slice.getLeft().getWidth(),
			pos.getY(),
			centerWidth,
			slice.getTop().getHeight()
		), slice.getTop(), true);
		//bottom
		drawTextureRectangle(new Recti(pos.getX() + slice.getLeft().getWidth(),
			pos.getY() + slice.getTop().getHeight() + centerHeight,
			centerWidth,
			slice.getTop().getHeight()
		), slice.getBottom(), true);
		//left
		drawTextureRectangle(new Recti(pos.getX(),
			pos.getY() + slice.getTop().getHeight(),
			slice.getLeft().getWidth(),
			centerHeight
		), slice.getLeft(), true);
		//right
		drawTextureRectangle(new Recti(pos.getX() +
			slice.getLeft().getWidth() +
			centerWidth,
			pos.getY() + slice.getTop().getHeight(),
			slice.getLeft().getWidth(),
			centerHeight
		), slice.getRight(), true);
	}

	@Override
	public void drawRectangle(Recti rect, Color color) {
		var tl = rect.getTopLeft();
		var tr = rect.getTopRight();
		var bl = rect.getBottomLeft();
		var br = rect.getBottomRight();

		//todo: make work with enabled textures

		glColor4f(color.getR() / 255.0f,
			color.getG() / 255.0f,
			color.getB() / 255.0f,
			color.getA() / 255.0f
		);

		//counterclockwise triangles
		glVertex2i(bl.getX(), bl.getY());
		glVertex2i(tr.getX(), tr.getY());
		glVertex2i(tl.getX(), tl.getY());

		glVertex2i(tr.getX(), tr.getY());
		glVertex2i(bl.getX(), bl.getY());
		glVertex2i(br.getX(), bl.getY());
	}

	@Override
	public void drawTexture(Vec2i pos, ITexture texture) {
		drawTextureRectangle(new Recti(pos, texture.getSize()), texture, true);
	}

	@Override
	public void drawTexture(Vec2i pos, ITexture texture, Color color) {
		drawTextureRectangle(new Recti(pos, texture.getSize()),
			texture,
			color,
			true
		);
	}

	@Override
	public void drawTextureRectangle(
		Recti rect, ITexture texture, boolean repeat
	) {
		drawTextureRectangle(rect, texture, Color.WHITE, repeat);
	}

	@Override
	public void drawTextureRectangle(
		Recti rect, ITexture texture, Color color, boolean repeat
	) {
		var tex = (Texture) texture;

		var tl = rect.getTopLeft();
		var tr = rect.getTopRight();
		var bl = rect.getBottomLeft();
		var br = rect.getBottomRight();

		var topleft = tex.getTexArea().getTopLeft();
		var size = repeat ? tex.getSize() : new Vec2i(100000, 100000);

		var ttl = Vec2i.ZERO;
		var ttr = new Vec2i(rect.getWidth(), 0);
		var tbl = new Vec2i(0, rect.getHeight());
		var tbr = new Vec2i(rect.getWidth(), rect.getHeight());

		if(!repeat) {
			ttr = Vec2i.sub(tex.getTexArea().getTopRight(), topleft);
			tbl = Vec2i.sub(tex.getTexArea().getBottomLeft(), topleft);
			tbr = Vec2i.sub(tex.getTexArea().getBottomRight(), topleft);
		}

		glUniform4f(tintIndex,
			color.getR() / 255.0f,
			color.getG() / 255.0f,
			color.getB() / 255.0f,
			color.getA() / 255.0f
		);

		glUniform2i(texOffsetIndex, topleft.getX(), topleft.getY());
		glUniform2i(texSizeIndex, size.getX(), size.getY());
		glBegin(GL_TRIANGLES);

		//counterclockwise triangles
		glVertexAttribI2i(texCoordIndex, tbl.getX(), tbl.getY());
		glVertex2i(bl.getX(), bl.getY());
		glVertexAttribI2i(texCoordIndex, ttr.getX(), ttr.getY());
		glVertex2i(tr.getX(), tr.getY());
		glVertexAttribI2i(texCoordIndex, ttl.getX(), ttl.getY());
		glVertex2i(tl.getX(), tl.getY());

		glVertexAttribI2i(texCoordIndex, ttr.getX(), ttr.getY());
		glVertex2i(tr.getX(), tr.getY());
		glVertexAttribI2i(texCoordIndex, tbl.getX(), tbl.getY());
		glVertex2i(bl.getX(), bl.getY());
		glVertexAttribI2i(texCoordIndex, tbr.getX(), tbr.getY());
		glVertex2i(br.getX(), bl.getY());
		glEnd();
	}
}
