/**
 * Grid Component
 *
 * Renders the canvas grid background with minor and major lines.
 */

import React from 'react';
import { useCanvasStyle } from '../providers/CanvasStyleProvider';
import type { PanOffset } from '../core/types';

export interface GridProps {
	pan: PanOffset;
	zoom: number;
	viewportWidth: number;
	viewportHeight: number;
	gridSize?: number;
	majorGridSize?: number;
}

/**
 * Canvas grid background
 */
export function Grid({ pan, zoom, viewportWidth, viewportHeight, gridSize = 50, majorGridSize = 250 }: GridProps) {
	const styles = useCanvasStyle();

	// Check visibility and basic requirements
	if (!styles.grid.visible || !viewportWidth || !viewportHeight || zoom <= 0) return null;

	const lines: React.ReactNode[] = [];

	// Colors from canvas style context
	const minorLineColor = styles.grid.minorLineColor;
	const majorLineColor = styles.grid.majorLineColor;
	const gridOpacity = styles.grid.opacity;

	const worldLeft = -pan.x / zoom;
	const worldTop = -pan.y / zoom;
	const worldRight = (-pan.x + viewportWidth) / zoom;
	const worldBottom = (-pan.y + viewportHeight) / zoom;

	// Minor Vertical lines
	const firstVerticalLine = Math.ceil(worldLeft / gridSize) * gridSize;
	for (let x = firstVerticalLine; x <= worldRight; x += gridSize) {
		if (x % majorGridSize !== 0) {
			lines.push(<line key={`v-${x}`} x1={x} y1={worldTop} x2={x} y2={worldBottom} stroke={minorLineColor} strokeWidth={1 / zoom} />);
		}
	}

	// Minor Horizontal lines
	const firstHorizontalLine = Math.ceil(worldTop / gridSize) * gridSize;
	for (let y = firstHorizontalLine; y <= worldBottom; y += gridSize) {
		if (y % majorGridSize !== 0) {
			lines.push(<line key={`h-${y}`} x1={worldLeft} y1={y} x2={worldRight} y2={y} stroke={minorLineColor} strokeWidth={1 / zoom} />);
		}
	}

	// Major Vertical lines
	const firstMajorVerticalLine = Math.ceil(worldLeft / majorGridSize) * majorGridSize;
	for (let x = firstMajorVerticalLine; x <= worldRight; x += majorGridSize) {
		lines.push(<line key={`major-v-${x}`} x1={x} y1={worldTop} x2={x} y2={worldBottom} stroke={majorLineColor} strokeWidth={1.5 / zoom} />);
	}

	// Major Horizontal lines
	const firstMajorHorizontalLine = Math.ceil(worldTop / majorGridSize) * majorGridSize;
	for (let y = firstMajorHorizontalLine; y <= worldBottom; y += majorGridSize) {
		lines.push(<line key={`major-h-${y}`} x1={worldLeft} y1={y} x2={worldRight} y2={y} stroke={majorLineColor} strokeWidth={1.5 / zoom} />);
	}

	return (
		<svg
			width="100%"
			height="100%"
			style={{
				position: 'absolute',
				top: 0,
				left: 0,
				overflow: 'visible',
				pointerEvents: 'none',
				opacity: gridOpacity,
			}}
		>
			<g>{lines}</g>
		</svg>
	);
}

export interface CrosshairsProps {
	pan: PanOffset;
	zoom: number;
	viewportWidth: number;
	viewportHeight: number;
	tickSize?: number;
	labelSize?: number;
}

/**
 * Coordinate axes with tick marks and labels
 */
export function Crosshairs({ pan, zoom, viewportWidth, viewportHeight, tickSize = 100, labelSize = 12 }: CrosshairsProps) {
	const styles = useCanvasStyle();

	// Check visibility and basic requirements
	if (!styles.axes.visible || !viewportWidth || !viewportHeight || zoom <= 0) return null;

	// Dynamic tick spacing based on zoom level
	const getAdjustedTickSize = () => {
		const minScreenSpacing = 80;
		const minWorldSpacing = minScreenSpacing / zoom;

		const niceNumbers = [50, 100, 250, 500, 1000, 2500, 5000, 10000];
		for (const n of niceNumbers) {
			if (n >= minWorldSpacing) {
				return Math.max(n, tickSize);
			}
		}
		return 10000;
	};

	const adjustedTickSize = getAdjustedTickSize();

	const elements: React.ReactNode[] = [];
	const strokeWidth = 1.5 / zoom;
	const tickLength = 5 / zoom;
	const labelOffset = 8 / zoom;
	const finalLabelSize = labelSize / zoom;

	// Colors from canvas style context
	const axisColor = styles.axes.color;
	const labelColor = styles.axes.labelColor;

	const worldLeft = -pan.x / zoom;
	const worldTop = -pan.y / zoom;
	const worldRight = (-pan.x + viewportWidth) / zoom;
	const worldBottom = (-pan.y + viewportHeight) / zoom;

	// X-axis line
	if (worldTop <= 0 && worldBottom >= 0) {
		elements.push(<line key="x-axis" x1={worldLeft} y1={0} x2={worldRight} y2={0} stroke={axisColor} strokeWidth={strokeWidth} />);
		const firstXTick = Math.ceil(worldLeft / adjustedTickSize) * adjustedTickSize;
		for (let x = firstXTick; x <= worldRight; x += adjustedTickSize) {
			if (x === 0 && worldLeft <= 0 && worldRight >= 0) continue;
			elements.push(
				<line key={`x-tick-${x}`} x1={x} y1={-tickLength} x2={x} y2={tickLength} stroke={axisColor} strokeWidth={strokeWidth / 1.5} />,
			);
			elements.push(
				<text key={`x-label-${x}`} x={x} y={tickLength + labelOffset} fill={labelColor} fontSize={finalLabelSize} textAnchor="middle" dominantBaseline="hanging">
					{x}
				</text>,
			);
		}
	}

	// Y-axis line
	if (worldLeft <= 0 && worldRight >= 0) {
		elements.push(<line key="y-axis" x1={0} y1={worldTop} x2={0} y2={worldBottom} stroke={axisColor} strokeWidth={strokeWidth} />);
		const firstYTick = Math.ceil(worldTop / adjustedTickSize) * adjustedTickSize;
		for (let y = firstYTick; y <= worldBottom; y += adjustedTickSize) {
			if (y === 0 && worldTop <= 0 && worldBottom >= 0) continue;
			elements.push(
				<line key={`y-tick-${y}`} x1={-tickLength} y1={y} x2={tickLength} y2={y} stroke={axisColor} strokeWidth={strokeWidth / 1.5} />,
			);
			elements.push(
				<text key={`y-label-${y}`} x={tickLength + labelOffset} y={y} fill={labelColor} fontSize={finalLabelSize} textAnchor="start" dominantBaseline="middle">
					{y}
				</text>,
			);
		}
	}

	// Origin Label (0,0)
	if (worldLeft <= 0 && worldRight >= 0 && worldTop <= 0 && worldBottom >= 0) {
		elements.push(
			<text
				key="origin-label"
				x={labelOffset}
				y={-labelOffset}
				fill={labelColor}
				fontSize={finalLabelSize * 1.1}
				textAnchor="start"
				dominantBaseline="alphabetic"
			>
				(0,0)
			</text>,
		);
	}

	return (
		<svg
			width="100%"
			height="100%"
			style={{
				position: 'absolute',
				top: 0,
				left: 0,
				overflow: 'visible',
				pointerEvents: 'none',
			}}
		>
			<g>{elements}</g>
		</svg>
	);
}
