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

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

const imageList = [
	{
		key: "card-color-1",
		src: "/static/assets/CardColorOne.png",
	},
	{
		key: "card-color-2",
		src: "/static/assets/CardColorTwo.png",
	},
	{
		key: "card-color-2-night",
		src: "/static/assets/CardColorTwoNight.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",
	},
	{
		key: "debt",
		src: "/static/assets/Debt.png",
	},
	{
		key: "potion",
		src: "/static/assets/Potion.png",
	},
	{
		key: "vp",
		src: "/static/assets/VP.png",
	},
	{
		key: "vp-token",
		src: "/static/assets/VP-Token.png",
	},
	{
		key: "sun",
		src: "/static/assets/Sun.png",
	},
];

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

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

export const loadFonts = async () => {
	const titleFont = new FontFace(
		"DominionTitle",
		`local("Trajan Pro Bold"), local("TrajanPro-Bold"), local('Trajan Pro'),
			url('https://fonts.cdnfonts.com/s/14928/TrajanPro-Bold.woff') format('woff'),
			url('https://shemitz.net/static/dominion3/Trajan%20Pro%20Bold.ttf') format('truetype'),
			url('https://dominion.games/fonts/TrajanPro-Bold.otf') format('opentype'),
			local("Trajan"),
			local("Optimus Princeps"),
			url(https://fonts.gstatic.com/s/cinzel/v8/8vIJ7ww63mVu7gt79mT7PkRXMw.woff2) format('woff2')`
	);

	const specialFont = new FontFace(
		"DominionSpecial",
		`local("Minion Std Black"), local("MinionStd-Black"), local("Minion Std"), local('Minion Pro'),
			url('https://fonts.cdnfonts.com/s/13260/MinionPro-Regular.woff') format('woff'),
			url('https://shemitz.net/static/dominion3/MinionStd-Black.otf') format('opentype'),
			local("Optimus Princeps"),
			url(https://fonts.gstatic.com/s/cinzel/v8/8vIJ7ww63mVu7gt79mT7PkRXMw.woff2) format('woff2')`
	);

	// deno-lint-ignore no-explicit-any
	(document.fonts as any).add(titleFont);
	// deno-lint-ignore no-explicit-any
	(document.fonts as any).add(specialFont);

	await Promise.all([titleFont.load(), specialFont.load()]);
};

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 _rgbCache: Record<string, { r: number; g: number; b: number }> = {};
const getColorRgb = (c: string): { r: number; g: number; b: number } => {
	const { rgb } = parseColor(c);
	const [r, g, b] = rgb;
	return { r, g, b };
	// if (c in _rgbCache) {
	// 	return _rgbCache[c]!;
	// }
	// const canvas = document.createElement("canvas");
	// canvas.width = 10;
	// canvas.height = 10;
	// const context = canvas.getContext("2d")!;
	// context.fillRect(0, 0, 10, 10);
	// const data = context.getImageData(5, 5, 1, 1).data;
	// console.log(data);
	// const [r, g, b] = data;
	// const rgb = { r: r!, g: g!, b: b! };
	// _rgbCache[c] = rgb;
	// return rgb;
};

const getTextColorForBackground = (c: string): string => {
	// return "black";
	const { r, g, b } = getColorRgb(c);
	const avg = (r + g + b) / 3 / 255;
	console.log([r, g, b], avg);
	return avg > 0.5 ? "black" : "white";
};

const getColors = (
	types: DominionCardType[]
): {
	primary: string;
	secondary: string | null;
	description: string | null;
	descriptionText: string;
	titleText: string;
} => {
	const descriptionType =
		types.find((t) => t.color?.onConflictDescriptionOnly) ?? null;
	const byPriority = [...types]
		.filter((type) => type.color && type !== descriptionType)
		.sort((a, b) => b.color!.priority - a.color!.priority);
	const priority1 = byPriority[0]!;
	let primaryType: DominionCardType | null = priority1 ?? null;
	let secondaryType = byPriority[1] ?? null;
	if (priority1 === TYPE_ACTION) {
		const overriders = byPriority.filter((t) => t.color!.overridesAction);
		if (overriders.length) {
			primaryType = overriders[0] ?? null;
		}
		if (primaryType === secondaryType) {
			secondaryType = byPriority[2] ?? null;
		}
	}
	primaryType = primaryType ?? descriptionType;
	const primary = primaryType?.color?.value ?? "white";
	const secondary = secondaryType?.color?.value ?? null;
	const description = descriptionType?.color?.value ?? null;
	const descriptionText = getTextColorForBackground(description ?? primary);
	const titleText = getTextColorForBackground(primary);
	return {
		primary,
		secondary,
		description,
		descriptionText,
		titleText,
	};
};

const drawStandardCard = async (
	context: CanvasRenderingContext2D,
	card: DominionCard & { orientation: "card" }
): Promise<void> => {
	const w = context.canvas.width;
	// const h = context.canvas.height;
	let size;
	context.save();
	// Draw the image
	const image = await loadImage(card.image);
	if (image) {
		const cx = w / 2;
		const cy = 704;
		const windowHeight = 830;
		const windowWidth = 1194;
		const scale = Math.max(
			windowHeight / image.height,
			windowWidth / image.width
		);
		context.drawImage(
			image,
			cx - (scale * image.width) / 2,
			cy - (scale * image.height) / 2,
			scale * image.width,
			scale * image.height
		);
	}
	// Draw the card base
	const colors = getColors(card.types); // "#ffbc55";

	if (colors.secondary) {
		context.drawImage(
			colorImage(getImage("card-color-1"), colors.secondary),
			0,
			0
		);
		context.drawImage(
			colorImage(getImage("card-color-2"), colors.primary),
			0,
			0
		);
	} else if (colors.description) {
		context.drawImage(
			colorImage(getImage("card-color-1"), colors.description),
			0,
			0
		);
		context.drawImage(
			colorImage(getImage("card-color-2-night"), colors.primary),
			0,
			0
		);
	} else {
		context.drawImage(
			colorImage(getImage("card-color-1"), colors.primary),
			0,
			0
		);
		context.drawImage(getImage("card-description-focus"), 44, 1094);
	}
	context.drawImage(getImage("card-gray"), 0, 0);
	context.drawImage(colorImage(getImage("card-brown"), "#ff9911"), 0, 0);
	// Draw the name
	context.fillStyle = colors.titleText;
	context.font = "90pt DominionText";
	const previewMeasure = await measureDominionText(
		context,
		parse(card.preview ?? "")
	);
	size = 78;
	context.font = `${size}pt DominionTitle`;
	while (
		(await measureDominionText(context, parse(card.title))).width >
		1050 - previewMeasure.width * 1.5
	) {
		size -= 1;
		context.font = `${size}pt DominionTitle`;
	}
	await renderDominionText(context, parse(card.title), w / 2, 220);
	// Draw the description
	context.fillStyle = colors.descriptionText;
	size = 60;
	context.font = `${size}pt DominionText`;
	while (
		(
			await measureDominionText(
				context,
				parse(card.description, { isDescription: true }),
				1000
			)
		).height > 650
	) {
		size -= 1;
		context.font = `${size}pt DominionText`;
	}
	await renderDominionText(
		context,
		parse(card.description, { isDescription: true }),
		w / 2,
		1490,
		1000
	);
	// Draw the types
	context.fillStyle = colors.titleText;
	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.fillStyle = colors.titleText;
	context.font = "90pt DominionText";
	const costMeasure = await measureDominionText(context, parse(card.cost));
	await renderDominionText(
		context,
		parse(card.cost),
		130 + costMeasure.width / 2,
		1940
	);
	// Draw the preview
	context.fillStyle = colors.titleText;
	if (card.preview) {
		context.font = "90pt DominionText";
		await renderDominionText(context, parse(card.preview), 200, 210);
		await renderDominionText(context, parse(card.preview), w - 200, 210);
	}
	// Draw the expansion icon
	// Draw the author credit
	context.fillStyle = "white";
	context.font = "31pt DominionText";
	const authorMeasure = await measureDominionText(
		context,
		parse(card.author)
	);
	await renderDominionText(
		context,
		parse(card.author),
		w - 150 - authorMeasure.width / 2,
		2035
	);
	// Draw the artist credit
	context.fillStyle = "white";
	const artistMeasure = await measureDominionText(
		context,
		parse(card.artist)
	);
	await renderDominionText(
		context,
		parse(card.artist),
		155 + artistMeasure.width / 2,
		2035
	);
	// Restore the context
	context.restore();
};

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