import * as React from "react";
import { settingsApi } from "../api/settings";

// Matches patterns like `src/main.rs:42` or `path/to/file.tsx:123`
// Path must contain at least one dot (file extension) and a colon followed by digits.
const CODE_REF_PATTERN = /\b([\w.\-/]+\.\w+):(\d+)\b/g;

export interface CodeRefPart {
	type: "text" | "ref";
	value: string;
	path?: string;
	line?: number;
}

/**
 * Parse a string into text and code-reference parts.
 * Code references have the format `path/to/file.ext:line`.
 */
export function parseCodeRefs(text: string): CodeRefPart[] {
	const parts: CodeRefPart[] = [];
	let lastIndex = 0;
	const re = new RegExp(CODE_REF_PATTERN.source, "g");
	let match: RegExpExecArray | null;

	match = re.exec(text);
	while (match !== null) {
		if (match.index > lastIndex) {
			parts.push({ type: "text", value: text.slice(lastIndex, match.index) });
		}
		parts.push({
			type: "ref",
			value: match[0],
			path: match[1],
			line: Number(match[2]),
		});
		lastIndex = re.lastIndex;
		match = re.exec(text);
	}

	if (lastIndex < text.length) {
		parts.push({ type: "text", value: text.slice(lastIndex) });
	}

	return parts;
}

interface CodeRefLinkProps {
	path: string;
	line: number;
	children: React.ReactNode;
}

function CodeRefLink({ path, line, children }: CodeRefLinkProps) {
	const handleClick = React.useCallback(() => {
		settingsApi.openFile(path, line).catch(() => {
			// Silently ignore errors (e.g. no editor configured)
		});
	}, [path, line]);

	return (
		<button
			type="button"
			onClick={handleClick}
			title={`Open ${path}:${line} in editor`}
			style={{
				background: "none",
				border: "none",
				padding: 0,
				cursor: "pointer",
				color: "#7ec8e3",
				fontFamily: "monospace",
				fontSize: "inherit",
				textDecoration: "underline",
				textDecorationStyle: "dotted",
			}}
		>
			{children}
		</button>
	);
}

interface InlineCodeWithRefsProps {
	text: string;
}

/**
 * Renders inline text with code references converted to clickable links.
 */
export function InlineCodeWithRefs({ text }: InlineCodeWithRefsProps) {
	const parts = parseCodeRefs(text);

	if (parts.length === 1 && parts[0].type === "text") {
		return <>{text}</>;
	}

	return (
		<>
			{parts.map((part) => {
				if (
					part.type === "ref" &&
					part.path !== undefined &&
					part.line !== undefined
				) {
					return (
						<CodeRefLink
							key={`ref-${part.path}:${part.line}`}
							path={part.path}
							line={part.line}
						>
							{part.value}
						</CodeRefLink>
					);
				}
				return <span key={`text-${part.value}`}>{part.value}</span>;
			})}
		</>
	);
}
