import { Paragraph, Spinner } from "@digdir/designsystemet-react";
import { getLocalizedString } from "@olenbetong/appframe-core";

import { CropCanvas } from "../../CropCanvas.js";
import { DragHandle } from "../../DragHandle.js";
import { EdgeHandle } from "../../EdgeHandle.js";
import { useZoomLevel } from "../zoomPlugin/ZoomContext.js";
import { useCropContext } from "./CropContext.js";

/** Canvas-area overlay for the crop tool. Reads all state from CropContext. */
export function CropOverlay() {
	let {
		imageUrl,
		activeCorners,
		mode,
		hasSelection,
		scale,
		displaySize,
		canvasRef,
		cvReady,
		cvError,
		cropping,
		error,
		handleCanvasReady,
		updateCorner,
		startRectDraw,
		updateRectDraw,
		finishRectDraw,
	} = useCropContext();

	let zoom = useZoomLevel();
	let showHandles = mode === "corners" && displaySize.width > 0;

	function pointerPosition(e: React.PointerEvent<HTMLDivElement>) {
		// getBoundingClientRect() is screen-space (affected by the zoom transform),
		// so divide by zoom to get back to the CSS-pixel space the tool expects.
		let rect = e.currentTarget.getBoundingClientRect();
		return { x: (e.clientX - rect.left) / zoom, y: (e.clientY - rect.top) / zoom };
	}

	function onPointerDown(e: React.PointerEvent<HTMLDivElement>) {
		e.currentTarget.setPointerCapture(e.pointerId);
		let { x, y } = pointerPosition(e);
		startRectDraw(x, y);
	}

	function onPointerMove(e: React.PointerEvent<HTMLDivElement>) {
		if (!(e.buttons & 1)) return;
		let { x, y } = pointerPosition(e);
		updateRectDraw(x, y);
	}

	return (
		<div className="crop-root">
			<div className="crop-inner">
				<CropCanvas ref={canvasRef} imageUrl={imageUrl} corners={activeCorners} onReady={handleCanvasReady} />

				{mode === "rect" && displaySize.width > 0 && (
					<div
						role="application"
						aria-label={getLocalizedString("Drag to draw a rectangle to crop to")}
						className="crop-draw-surface"
						onPointerDown={onPointerDown}
						onPointerMove={onPointerMove}
						onPointerUp={finishRectDraw}
						onPointerCancel={finishRectDraw}
					/>
				)}

				{showHandles &&
					activeCorners.map((corner, i) => (
						<DragHandle
							key={i}
							x={corner.x * scale}
							y={corner.y * scale}
							onChange={(x, y) => updateCorner(i, x, y)}
							containerWidth={displaySize.width}
							containerHeight={displaySize.height}
						/>
					))}

				{showHandles &&
					(() => {
						let [tl, tr, br, bl] = activeCorners;
						let s = scale;
						return (
							<>
								{/* Top edge — moves TL (0) and TR (1) */}
								<EdgeHandle
									x={((tl.x + tr.x) / 2) * s}
									y={((tl.y + tr.y) / 2) * s}
									axis="y"
									onChange={(dx, dy) => {
										updateCorner(0, tl.x * s + dx, tl.y * s + dy);
										updateCorner(1, tr.x * s + dx, tr.y * s + dy);
									}}
								/>
								{/* Right edge — moves TR (1) and BR (2) */}
								<EdgeHandle
									x={((tr.x + br.x) / 2) * s}
									y={((tr.y + br.y) / 2) * s}
									axis="x"
									onChange={(dx, dy) => {
										updateCorner(1, tr.x * s + dx, tr.y * s + dy);
										updateCorner(2, br.x * s + dx, br.y * s + dy);
									}}
								/>
								{/* Bottom edge — moves BR (2) and BL (3) */}
								<EdgeHandle
									x={((br.x + bl.x) / 2) * s}
									y={((br.y + bl.y) / 2) * s}
									axis="y"
									onChange={(dx, dy) => {
										updateCorner(2, br.x * s + dx, br.y * s + dy);
										updateCorner(3, bl.x * s + dx, bl.y * s + dy);
									}}
								/>
								{/* Left edge — moves BL (3) and TL (0) */}
								<EdgeHandle
									x={((bl.x + tl.x) / 2) * s}
									y={((bl.y + tl.y) / 2) * s}
									axis="x"
									onChange={(dx, dy) => {
										updateCorner(3, bl.x * s + dx, bl.y * s + dy);
										updateCorner(0, tl.x * s + dx, tl.y * s + dy);
									}}
								/>
							</>
						);
					})()}
			</div>

			{/* Status line. OpenCV only powers the border suggestion, so a load failure is
			    informational — cropping stays available either way. */}
			{cropping ? (
				<div className="crop-loading">
					<Spinner aria-hidden data-size="xs" />
				</div>
			) : error ? (
				<div className="crop-loading">
					<Paragraph data-size="sm">{error}</Paragraph>
				</div>
			) : mode === "rect" ? (
				<div className="crop-loading">
					<Paragraph data-size="sm">
						{hasSelection
							? getLocalizedString("Release to use this rectangle")
							: getLocalizedString("Drag to draw a rectangle to crop to")}
					</Paragraph>
				</div>
			) : !cvReady && !cvError ? (
				<div className="crop-loading">
					<Spinner aria-hidden data-size="xs" />
					<Paragraph data-size="sm">{getLocalizedString("Detecting borders…")}</Paragraph>
				</div>
			) : cvError ? (
				<div className="crop-loading">
					<Paragraph data-size="sm">
						{getLocalizedString("Automatic border detection is unavailable. Adjust the selection manually.")}
					</Paragraph>
				</div>
			) : null}
		</div>
	);
}
