import {
	measureDominionText,
	parse,
	renderDominionText,
} from "./dominiontext.ts";
import { DominionCardType, DominionColor, TYPE_ACTION } from "./types.ts";
import { DominionCard } from "./types.ts";

const imageCache: Record<string, HTMLImageElement> = {};
export const loadImage = (
	key: string,
	src: string
): Promise<HTMLImageElement> => {
	return new Promise((resolve) => {
		if (key in imageCache && imageCache[key]) {
			resolve(imageCache[key]);
		}
		const img = new Image();
		img.onload = () => {
			imageCache[key] = img;
			resolve(img);
		};
		img.onerror = (e) => {
			console.log("err", e);
		};
		img.src = src;
	});
};

const imageList = [
	{
		key: "card-color-1",
		src: "/static/assets/CardColorOne.png",
	},
	{
		key: "card-brown",
		src: "/static/assets/CardBrown.png",
	},
	{
		key: "card-gray",
		src: "/static/assets/CardGray.png",
	},
	{
		key: "card-description-focus",
		src: "/static/assets/DescriptionFocus.png",
	},
	{
		key: "coin",
		src: "/static/assets/Coin.png",
	},
];

export const loadImages = async () => {
	for (const imageInfo of imageList) {
		const { key, src } = imageInfo;
		await loadImage(key, src);
	}
};

export const getImage = (key: string) => {
	const image = imageCache[key];
	if (!image) {
		throw Error(`Tried to get an invalid image ${key}`);
	}
	return image;
};

export const colorImage = (
	image: HTMLImageElement,
	color?: string
): HTMLCanvasElement => {
	const canvas = document.createElement("canvas");
	canvas.width = image.width;
	canvas.height = image.height;
	const context = canvas.getContext("2d")!;
	context.save();
	context.drawImage(image, 0, 0);
	context.globalCompositeOperation = "multiply";
	context.fillStyle = color ?? "white";
	context.fillRect(0, 0, canvas.width, canvas.height);
	context.globalCompositeOperation = "destination-atop"; // restore transparency
	context.drawImage(image, 0, 0);
	context.restore();
	return canvas;
};

export const drawCard = (
	context: CanvasRenderingContext2D,
	card: DominionCard
): Promise<void> => {
	if (card.orientation === "card") {
		return drawStandardCard(context, card);
	} else {
		return drawLandscapeCard(context, card);
	}
};

const getColors = (types: DominionCardType[]): { primary: string } => {
	const byPriority = [...types]
		.filter((type) => type.color)
		.sort((a, b) => b.color!.priority - a.color!.priority);
	if (byPriority.length === 0) {
		return { primary: "white" };
	}
	const priority = byPriority[0]!;
	if (priority !== TYPE_ACTION) {
		return { primary: priority.color!.value };
	} else {
		const overriders = byPriority.filter((t) => t.color!.overridesAction);
		if (overriders.length) {
			return { primary: overriders[0]!.color!.value };
		} else {
			return { primary: priority.color!.value };
		}
	}
};

const drawStandardCard = async (
	context: CanvasRenderingContext2D,
	card: DominionCard & { orientation: "card" }
): Promise<void> => {
	const w = context.canvas.width;
	const h = context.canvas.height;
	context.save();
	// Draw the image
	// Draw the card base
	const color = getColors(card.types).primary; // "#ffbc55";
	context.drawImage(colorImage(getImage("card-color-1"), color), 0, 0);
	context.drawImage(getImage("card-gray"), 0, 0);
	context.drawImage(colorImage(getImage("card-brown"), "#ff9911"), 0, 0);
	context.drawImage(getImage("card-description-focus"), 44, 1094);
	// Draw the name
	context.font = "78pt DominionTitle";
	await renderDominionText(context, parse(card.title), w / 2, 220, 1100);
	// Draw the description
	context.font = "60pt DominionText";
	await renderDominionText(
		context,
		parse(card.description),
		w / 2,
		1520,
		1100
	);
	// Draw the types
	let size = 65;
	context.font = `${size}pt DominionTitle`;
	while (
		(
			await measureDominionText(
				context,
				parse(card.types.map((t) => t.name).join(" - "))
			)
		).width > 800
	) {
		size -= 1;
		context.font = `${size}pt DominionTitle`;
	}
	await renderDominionText(
		context,
		parse(card.types.map((t) => t.name).join(" - ")),
		w / 2,
		1930,
		800
	);
	// Draw the cost
	context.font = "90pt DominionText";
	await renderDominionText(context, parse(card.cost), 210, 1940, 200);
	// Draw the preview
	if (card.preview) {
		context.font = "90pt DominionText";
		await renderDominionText(context, parse(card.preview), 200, 210, 200);
		await renderDominionText(
			context,
			parse(card.preview),
			w - 200,
			210,
			200
		);
	}
	// Draw the icon
	// Draw the credit
	context.restore();
};

const drawLandscapeCard = async (
	context: CanvasRenderingContext2D,
	card: DominionCard & { orientation: "landscape" }
): Promise<void> => {
	// TODO: everything
};
