import { X509Certificate } from "node:crypto";
import { getHostname } from "tldts";

/**
 * Safely parses a value that might be a JSON string or already a parsed object.
 * This handles cases where ORMs like Drizzle might return already parsed objects
 * instead of JSON strings from TEXT/JSON columns.
 *
 * @param value - The value to parse (string, object, null, or undefined)
 * @returns The parsed object or null
 * @throws Error if string parsing fails
 */
export function safeJsonParse<T>(
	value: string | T | null | undefined,
): T | null {
	if (!value) return null;

	if (typeof value === "object") {
		return value as T;
	}

	if (typeof value === "string") {
		try {
			return JSON.parse(value) as T;
		} catch (error) {
			throw new Error(
				`Failed to parse JSON: ${error instanceof Error ? error.message : "Unknown error"}`,
			);
		}
	}

	return null;
}

/**
 * Checks if a domain matches any domain in a comma-separated list.
 */
export const domainMatches = (searchDomain: string, domainList: string) => {
	const search = searchDomain.toLowerCase();
	const domains = domainList
		.split(",")
		.map((d) => d.trim().toLowerCase())
		.filter(Boolean);
	return domains.some((d) => search === d || search.endsWith(`.${d}`));
};

/**
 * Validates email domain against allowed domain(s).
 * Supports comma-separated domains for multi-domain SSO.
 */
export const validateEmailDomain = (email: string, domain: string) => {
	const emailDomain = email.split("@")[1]?.toLowerCase();
	if (!emailDomain || !domain) {
		return false;
	}
	return domainMatches(emailDomain, domain);
};

export function parseCertificate(certPem: string) {
	// SAML metadata X509Certificate elements contain raw base64 without PEM headers,
	// but users may also provide full PEM-formatted certificates. Normalize to PEM.
	const normalized = certPem.includes("-----BEGIN")
		? certPem
		: `-----BEGIN CERTIFICATE-----\n${certPem}\n-----END CERTIFICATE-----`;

	const cert = new X509Certificate(normalized);

	return {
		fingerprintSha256: cert.fingerprint256,
		notBefore: cert.validFrom,
		notAfter: cert.validTo,
		publicKeyAlgorithm:
			cert.publicKey.asymmetricKeyType?.toUpperCase() || "UNKNOWN",
	};
}

export function getHostnameFromDomain(domain: string): string | null {
	return getHostname(domain) || null;
}

export function maskClientId(clientId: string): string {
	if (clientId.length <= 4) {
		return "****";
	}
	return `****${clientId.slice(-4)}`;
}
