import { createLogger } from "../utils/logger/index.js";
import { init_logger } from "../utils/logger.js";
import { resolveSiteShareConfig } from "./site-share-config.js";
import "./share-store.js";
import { getSiteShareStore } from "./site-share-store.js";
import { getClientIpFromHeaders } from "../gateway/security/loopback.js";
import { serveStaticSiteRequest } from "./site-static-serve.js";
import { forwardHttpRequest, handleProxyWebSocketUpgrade } from "./site-proxy.js";
import { renderShareExpiredPage } from "./share-landing.js";
//#region src/share/site-share-router.ts
init_logger();
const log = createLogger("SiteShareRouter");
const SITE_SUBPATH_PREFIX = "/site/";
/**
* Extract the share label from the request Host header when the public host
* suffix matches. Returns `null` if the request did not target a site-share
* subdomain.
*/
function extractSiteShareLabel(host, suffix) {
	if (!host) return null;
	const lowered = host.toLowerCase().split(":")[0];
	const normSuffix = suffix.toLowerCase();
	if (lowered === normSuffix) return null;
	if (!lowered.endsWith(`.${normSuffix}`)) return null;
	const label = lowered.slice(0, -1 * (normSuffix.length + 1));
	if (!label || label.includes(".")) return null;
	return label;
}
/**
* Hono middleware. Intercepts requests whose Host header is `*.share.xopc.ai`
* (or matches the configured suffix), routes them to the matching site share.
* Falls through to next() when the host does not match.
*
* Also handles the subpath fallback `/site/:token/*` for environments without
* wildcard DNS — same handler logic, just different prefix extraction.
*/
function createSiteShareMiddleware(service) {
	return async (c, next) => {
		const config = resolveSiteShareConfig(service);
		if (!config.enabled) return next();
		const store = getSiteShareStore(config);
		store.updateConfig(config);
		const label = extractSiteShareLabel(c.req.header("host"), config.publicHostSuffix);
		const url = new URL(c.req.url);
		const clientIp = getClientIpFromHeaders({ get: (n) => c.req.header(n) ?? void 0 });
		let record = null;
		let innerPath = url.pathname;
		let basePrefix = "";
		if (label) {
			record = store.resolveByHostLabel(label);
			if (!record) return next();
		} else if (url.pathname.startsWith(SITE_SUBPATH_PREFIX)) {
			const rest = url.pathname.slice(6);
			const slash = rest.indexOf("/");
			const token = slash < 0 ? rest : rest.slice(0, slash);
			const tail = slash < 0 ? "" : rest.slice(slash);
			record = store.getByToken(token) ?? store.getBySubdomain(token);
			if (!record) return next();
			innerPath = tail || "/";
			basePrefix = `${SITE_SUBPATH_PREFIX}${token}`;
		} else return next();
		const validation = store.validateAccess(record);
		if (!validation.valid) return c.html(renderShareExpiredPage(validation.reason), 410);
		if (record.source.kind === "static") try {
			const result = await serveStaticSiteRequest(record, innerPath, basePrefix);
			store.recordRequest(record.id, clientIp);
			return result;
		} catch (err) {
			log.warn({
				err,
				shareId: record.id
			}, "static serve failed");
			return new Response("Internal error", { status: 500 });
		}
		if (record.source.kind === "proxy") {
			const ctx = {
				innerPath,
				basePrefix,
				clientIp,
				originalUrl: url,
				forwardedProto: url.protocol === "https:" ? "https" : "http"
			};
			const { response } = await forwardHttpRequest(record, store, c.req.raw, ctx);
			return response;
		}
		return next();
	};
}
/** Standalone HTTP upgrade handler that bridges WebSocket requests to the proxy share. */
function handleSiteShareUpgrade(service, req, socket, head) {
	const config = resolveSiteShareConfig(service);
	if (!config.enabled) return false;
	if (!config.proxy.enabled || !config.proxy.forwardWebSocket) return false;
	const store = getSiteShareStore(config);
	store.updateConfig(config);
	const host = (req.headers.host ?? "").toString();
	const label = extractSiteShareLabel(host, config.publicHostSuffix);
	const url = new URL(req.url ?? "/", `http://${host || "localhost"}`);
	let record = null;
	let innerPath = url.pathname;
	let basePrefix = "";
	if (label) record = store.resolveByHostLabel(label);
	else if (url.pathname.startsWith(SITE_SUBPATH_PREFIX)) {
		const rest = url.pathname.slice(6);
		const slash = rest.indexOf("/");
		const token = slash < 0 ? rest : rest.slice(0, slash);
		const tail = slash < 0 ? "" : rest.slice(slash);
		record = store.getByToken(token) ?? store.getBySubdomain(token);
		innerPath = tail || "/";
		basePrefix = `${SITE_SUBPATH_PREFIX}${token}`;
	}
	if (!record) return false;
	if (!store.validateAccess(record).valid) {
		try {
			socket.write("HTTP/1.1 410 Gone\r\nConnection: close\r\n\r\n");
		} catch {}
		socket.destroy();
		return true;
	}
	if (record.source.kind !== "proxy") {
		try {
			socket.write("HTTP/1.1 400 Bad Request\r\nConnection: close\r\n\r\n");
		} catch {}
		socket.destroy();
		return true;
	}
	const clientIp = (req.socket.remoteAddress ?? "").replace(/^::ffff:/, "") || "0.0.0.0";
	handleProxyWebSocketUpgrade({
		record,
		store,
		req,
		socket,
		head,
		innerPath,
		basePrefix,
		clientIp
	});
	return true;
}
/** Register the middleware on a Hono app — call from createHonoApp. */
function registerSiteShareMiddleware(app, service) {
	app.use(createSiteShareMiddleware(service));
}
//#endregion
export { createSiteShareMiddleware, extractSiteShareLabel, handleSiteShareUpgrade, registerSiteShareMiddleware };

//# sourceMappingURL=site-share-router.js.map