import { readFile } from "node:fs/promises";
import path from "node:path";
import type { Metadata } from "next";
import Image from "next/image";
import { notFound } from "next/navigation";
import type { ReactNode } from "react";

const technicalDocs = {
	"01-base-runtime": {
		title: "基座 Runtime",
		file: "01-base-runtime.md",
		image: "/doc-assets/technical/01-base-runtime.png",
	},
	"02-agent-loop": {
		title: "Agent Loop",
		file: "02-agent-loop.md",
		image: "/doc-assets/technical/02-agent-loop.png",
	},
	"03-tools": {
		title: "工具体系",
		file: "03-tools.md",
		image: "/doc-assets/technical/03-tools.png",
	},
	"04-skills": {
		title: "Skill 体系",
		file: "04-skills.md",
		image: "/doc-assets/technical/04-skills.png",
	},
	"05-workspace-memory-observability": {
		title: "工作区、运行态和记忆",
		file: "05-workspace-memory-observability.md",
		image: "/doc-assets/technical/05-workspace-memory-observability.png",
	},
	"06-product-data": {
		title: "product-data",
		file: "06-product-data.md",
		image: "/doc-assets/technical/06-product-data.png",
	},
	"07-online-mining-v2": {
		title: "online-mining-v2",
		file: "07-online-mining-v2.md",
		image: "/doc-assets/technical/07-online-mining-v2.png",
	},
	"08-label-master": {
		title: "标签大师",
		file: "08-label-master.md",
		image: "/doc-assets/technical/08-label-master.png",
	},
	"09-external-skills": {
		title: "外部系统 Skill",
		file: "09-external-skills.md",
		image: "/doc-assets/technical/09-external-skills.png",
	},
	"10-memory-research": {
		title: "Agent 记忆机制调研与对比",
		file: "10-memory-research.md",
		image: null,
	},
	"11-subagents": {
		title: "子 Agent 使用边界",
		file: "11-subagents.md",
		image: null,
	},
	"12-runtime-guidance-queue": {
		title: "运行中输入队列",
		file: "12-runtime-guidance-queue.md",
		image: null,
	},
} as const;

type TechnicalDocSlug = keyof typeof technicalDocs;

function getDoc(slug: string) {
	if (slug in technicalDocs) {
		return technicalDocs[slug as TechnicalDocSlug];
	}
	return null;
}

function markdownPath(file: string) {
	return path.join(
		process.cwd(),
		"public",
		"doc-assets",
		"technical-docs",
		file,
	);
}

function normalizeMarkdown(markdown: string) {
	return markdown
		.replace(/^\s*#\s+.+\n+/, "")
		.replaceAll("](assets/", "](/doc-assets/technical/");
}

function parseInline(text: string): ReactNode[] {
	const nodes: ReactNode[] = [];
	const pattern = /(`[^`]+`|\*\*[^*]+\*\*|\[([^\]]+)\]\(([^)]+)\))/g;
	let cursor = 0;

	while (true) {
		const match = pattern.exec(text);
		if (match === null) break;
		if (match.index > cursor) {
			nodes.push(text.slice(cursor, match.index));
		}

		const token = match[0];
		const key = `${match.index}-${token}`;
		if (token.startsWith("`")) {
			nodes.push(<code key={key}>{token.slice(1, -1)}</code>);
		} else if (token.startsWith("**")) {
			nodes.push(<strong key={key}>{token.slice(2, -2)}</strong>);
		} else {
			const href = match[3] ?? "";
			const isExternal = /^https?:\/\//.test(href);
			nodes.push(
				<a
					href={href}
					key={key}
					rel={isExternal ? "noopener" : undefined}
					target={isExternal ? "_blank" : undefined}
				>
					{match[2]}
				</a>,
			);
		}

		cursor = pattern.lastIndex;
	}

	if (cursor < text.length) {
		nodes.push(text.slice(cursor));
	}

	return nodes;
}

function splitTableRow(line: string) {
	return line
		.trim()
		.replace(/^\|/, "")
		.replace(/\|$/, "")
		.split("|")
		.map((cell) => cell.trim());
}

function isTableDivider(line: string) {
	return /^\|?\s*:?-{3,}:?\s*(\|\s*:?-{3,}:?\s*)+\|?\s*$/.test(line);
}

function startsBlock(line: string, nextLine?: string) {
	return (
		line.startsWith("```") ||
		/^#{1,6}\s+/.test(line) ||
		/^[-*]\s+/.test(line) ||
		/^\d+\.\s+/.test(line) ||
		/^>\s?/.test(line) ||
		/^!\[[^\]]*]\([^)]+\)\s*$/.test(line) ||
		(line.includes("|") && nextLine !== undefined && isTableDivider(nextLine))
	);
}

function renderHeading(depth: number, text: string, key: string) {
	if (depth === 1) return <h1 key={key}>{parseInline(text)}</h1>;
	if (depth === 2) return <h2 key={key}>{parseInline(text)}</h2>;
	if (depth === 3) return <h3 key={key}>{parseInline(text)}</h3>;
	if (depth === 4) return <h4 key={key}>{parseInline(text)}</h4>;
	if (depth === 5) return <h5 key={key}>{parseInline(text)}</h5>;
	return <h6 key={key}>{parseInline(text)}</h6>;
}

function renderMarkdown(markdown: string) {
	const lines = markdown.replace(/\r\n/g, "\n").split("\n");
	const blocks: ReactNode[] = [];
	let index = 0;

	while (index < lines.length) {
		const line = lines[index];
		const trimmed = line.trim();
		if (!trimmed) {
			index += 1;
			continue;
		}

		if (trimmed.startsWith("```")) {
			const language = trimmed.slice(3).trim() || "text";
			const codeLines: string[] = [];
			index += 1;
			while (index < lines.length && !lines[index].trim().startsWith("```")) {
				codeLines.push(lines[index]);
				index += 1;
			}
			if (index < lines.length) index += 1;
			blocks.push(
				<div className="project-doc-code-block" key={`code-${index}`}>
					<div>{language}</div>
					<pre>
						<code>{codeLines.join("\n")}</code>
					</pre>
				</div>,
			);
			continue;
		}

		const heading = trimmed.match(/^(#{1,6})\s+(.*)$/);
		if (heading) {
			blocks.push(
				renderHeading(heading[1].length, heading[2], `heading-${index}`),
			);
			index += 1;
			continue;
		}

		const image = trimmed.match(/^!\[([^\]]*)]\(([^)]+)\)\s*$/);
		if (image) {
			blocks.push(
				<Image
					alt={image[1]}
					height={900}
					key={`image-${index}`}
					src={image[2]}
					width={1600}
				/>,
			);
			index += 1;
			continue;
		}

		if (
			trimmed.includes("|") &&
			index + 1 < lines.length &&
			isTableDivider(lines[index + 1])
		) {
			const headers = splitTableRow(trimmed);
			index += 2;
			const rows: string[][] = [];
			while (index < lines.length && lines[index].trim().includes("|")) {
				rows.push(splitTableRow(lines[index]));
				index += 1;
			}
			blocks.push(
				<table key={`table-${index}`}>
					<thead>
						<tr>
							{headers.map((cell) => (
								<th key={cell}>{parseInline(cell)}</th>
							))}
						</tr>
					</thead>
					<tbody>
						{rows.map((row) => (
							<tr key={row.join("|")}>
								{row.map((cell) => (
									<td key={`${row.join("|")}-${cell}`}>{parseInline(cell)}</td>
								))}
							</tr>
						))}
					</tbody>
				</table>,
			);
			continue;
		}

		if (/^[-*]\s+/.test(trimmed)) {
			const items: string[] = [];
			while (index < lines.length && /^[-*]\s+/.test(lines[index].trim())) {
				items.push(lines[index].trim().replace(/^[-*]\s+/, ""));
				index += 1;
			}
			blocks.push(
				<ul key={`ul-${index}`}>
					{items.map((item) => (
						<li key={item}>{parseInline(item)}</li>
					))}
				</ul>,
			);
			continue;
		}

		if (/^\d+\.\s+/.test(trimmed)) {
			const items: string[] = [];
			while (index < lines.length && /^\d+\.\s+/.test(lines[index].trim())) {
				items.push(lines[index].trim().replace(/^\d+\.\s+/, ""));
				index += 1;
			}
			blocks.push(
				<ol key={`ol-${index}`}>
					{items.map((item) => (
						<li key={item}>{parseInline(item)}</li>
					))}
				</ol>,
			);
			continue;
		}

		if (/^>\s?/.test(trimmed)) {
			const quoteLines: string[] = [];
			while (index < lines.length && /^>\s?/.test(lines[index].trim())) {
				quoteLines.push(lines[index].trim().replace(/^>\s?/, ""));
				index += 1;
			}
			blocks.push(
				<blockquote key={`quote-${index}`}>
					{parseInline(quoteLines.join(" "))}
				</blockquote>,
			);
			continue;
		}

		const paragraphLines = [trimmed];
		index += 1;
		while (
			index < lines.length &&
			lines[index].trim() &&
			!startsBlock(lines[index].trim(), lines[index + 1]?.trim())
		) {
			paragraphLines.push(lines[index].trim());
			index += 1;
		}
		blocks.push(
			<p key={`p-${index}`}>{parseInline(paragraphLines.join(" "))}</p>,
		);
	}

	return blocks;
}

export function generateStaticParams() {
	return Object.keys(technicalDocs).map((slug) => ({ slug }));
}

export async function generateMetadata({
	params,
}: {
	params: Promise<{ slug: string }>;
}): Promise<Metadata> {
	const { slug } = await params;
	const doc = getDoc(slug);
	if (!doc) return {};
	return {
		title: `${doc.title} - ZK Data Agent`,
	};
}

export default async function TechnicalDocPage({
	params,
}: {
	params: Promise<{ slug: string }>;
}) {
	const { slug } = await params;
	const doc = getDoc(slug);
	if (!doc) notFound();

	const rawMarkdown = await readFile(markdownPath(doc.file), "utf8");
	const markdown = normalizeMarkdown(rawMarkdown);

	return (
		<main className="project-doc-page project-doc-detail-page">
			<header className="project-doc-detail-hero">
				<nav className="project-doc-nav">
					<a href="/doc">ZK Data Agent</a>
					<div>
						<a href="/doc">返回总览</a>
					</div>
				</nav>
				<div className="project-doc-detail-head">
					<p className="project-doc-kicker">技术文档</p>
					<h1>{doc.title}</h1>
					<a className="project-doc-back-link" href="/doc">
						返回架构总览
					</a>
				</div>
			</header>

			<section className="project-doc-detail-shell">
				<article className="project-doc-article">
					{renderMarkdown(markdown)}
				</article>
			</section>
		</main>
	);
}
