import { forwardRef, useEffect, useImperativeHandle, useRef } from "react";

import type { Quad } from "./useEdgeDetection.js";

const MAX_DISPLAY_WIDTH = 1600;

export interface CropCanvasHandle {
	/** Returns a canvas with the clean image (no overlay) for use with cv.imread. */
	getCleanCanvas(): HTMLCanvasElement | null;
}

interface Props {
	imageUrl: string;
	corners: Quad;
	onReady?: (canvas: HTMLCanvasElement, width: number, height: number) => void;
}

function drawOverlay(ctx: CanvasRenderingContext2D, width: number, height: number, corners: Quad) {
	let [tl, tr, br, bl] = corners;

	ctx.save();

	// Dark overlay with polygon cutout (even-odd fill rule creates a "window")
	ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
	ctx.beginPath();
	ctx.rect(0, 0, width, height);
	ctx.moveTo(tl.x, tl.y);
	ctx.lineTo(tr.x, tr.y);
	ctx.lineTo(br.x, br.y);
	ctx.lineTo(bl.x, bl.y);
	ctx.closePath();
	ctx.fill("evenodd");

	// Selection border
	ctx.strokeStyle = "#2196f3";
	ctx.lineWidth = Math.max(2, width * 0.003);
	ctx.beginPath();
	ctx.moveTo(tl.x, tl.y);
	ctx.lineTo(tr.x, tr.y);
	ctx.lineTo(br.x, br.y);
	ctx.lineTo(bl.x, bl.y);
	ctx.closePath();
	ctx.stroke();

	ctx.restore();
}

/**
 * Renders the image on a canvas with a perspective-crop overlay.
 * Exposes `getImageData()` so callers can extract pixels for off-thread processing.
 */
export let CropCanvas = forwardRef<CropCanvasHandle, Props>(function CropCanvas({ imageUrl, corners, onReady }, ref) {
	let canvasRef = useRef<HTMLCanvasElement>(null);
	let imageRef = useRef<HTMLImageElement | null>(null);

	useEffect(() => {
		let img = new Image();
		img.onload = () => {
			imageRef.current = img;
			let canvas = canvasRef.current;
			if (!canvas) return;

			let scale = Math.min(1, MAX_DISPLAY_WIDTH / img.naturalWidth);
			canvas.width = Math.round(img.naturalWidth * scale);
			canvas.height = Math.round(img.naturalHeight * scale);

			let ctx = canvas.getContext("2d");
			ctx?.drawImage(img, 0, 0, canvas.width, canvas.height);
			drawOverlay(ctx!, canvas.width, canvas.height, corners);
			onReady?.(canvas, canvas.width, canvas.height);
		};
		img.src = imageUrl;
	}, [imageUrl]); // eslint-disable-line react-hooks/exhaustive-deps

	// Redraw overlay whenever corners change
	useEffect(() => {
		let canvas = canvasRef.current;
		let img = imageRef.current;
		if (!canvas || !img) return;
		let ctx = canvas.getContext("2d");
		if (!ctx) return;
		ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
		drawOverlay(ctx, canvas.width, canvas.height, corners);
	}, [corners]);

	useImperativeHandle(ref, () => ({
		getCleanCanvas(): HTMLCanvasElement | null {
			let canvas = canvasRef.current;
			let img = imageRef.current;
			if (!canvas || !img) return null;
			let clean = document.createElement("canvas");
			clean.width = canvas.width;
			clean.height = canvas.height;
			clean.getContext("2d")?.drawImage(img, 0, 0, canvas.width, canvas.height);
			return clean;
		},
	}));

	return <canvas ref={canvasRef} style={{ display: "block", maxWidth: "100%", height: "auto" }} />;
});
