import { logger } from "../logger/index.mjs";
import { getDBClient } from "../utils/mongoDB/connectDB.mjs";
import { configurationFilesCandidates } from "@intlayer/config";
import { ObjectId } from "mongodb";

//#region src/services/gitlab.service.ts
const GITLAB_DEFAULT_URL = "https://gitlab.com";
/**
* Get GitLab authorization URL for OAuth flow
*/
const getAuthorizationUrl = (redirectUri, instanceUrl, login) => {
	const clientId = process.env.GITLAB_CLIENT_ID;
	const baseUrl = instanceUrl || GITLAB_DEFAULT_URL;
	if (!clientId) throw new Error("GitLab Client ID is not configured");
	const params = new URLSearchParams({
		client_id: clientId,
		redirect_uri: redirectUri,
		response_type: "code",
		scope: "api read_repository",
		state: "gitlab_oauth"
	});
	if (login) params.append("login_hint", login);
	return `${baseUrl}/oauth/authorize?${params.toString()}`;
};
/**
* Exchange GitLab authorization code for access token
*/
const exchangeCodeForToken = async (code, redirectUri, instanceUrl) => {
	const clientId = process.env.GITLAB_CLIENT_ID;
	const clientSecret = process.env.GITLAB_CLIENT_SECRET;
	const baseUrl = instanceUrl || GITLAB_DEFAULT_URL;
	if (!clientId || !clientSecret) throw new Error("GitLab OAuth credentials are not configured");
	try {
		const response = await fetch(`${baseUrl}/oauth/token`, {
			method: "POST",
			headers: {
				"Content-Type": "application/json",
				Accept: "application/json"
			},
			body: JSON.stringify({
				client_id: clientId,
				client_secret: clientSecret,
				code,
				grant_type: "authorization_code",
				redirect_uri: redirectUri
			})
		});
		if (!response.ok) throw new Error(`GitLab token exchange failed: ${response.statusText}`);
		const data = await response.json();
		if (data.error) throw new Error(`GitLab token error: ${data.error_description}`);
		return data.access_token;
	} catch (error) {
		logger.error("Error exchanging GitLab code for token:", error);
		throw error;
	}
};
/**
* Get user's GitLab projects/repositories
*/
const getUserProjects = async (accessToken, instanceUrl) => {
	const baseUrl = instanceUrl || GITLAB_DEFAULT_URL;
	try {
		const response = await fetch(`${baseUrl}/api/v4/projects?membership=true&order_by=last_activity_at&per_page=100`, { headers: {
			Authorization: `Bearer ${accessToken}`,
			Accept: "application/json"
		} });
		if (!response.ok) throw new Error(`Failed to fetch GitLab projects: ${response.statusText}`);
		return await response.json();
	} catch (error) {
		logger.error("Error fetching GitLab projects:", error);
		throw error;
	}
};
/**
* Check if valid intlayer configuration files exist in a GitLab repository (Recursively).
* Returns an array of file paths found.
*/
const checkIntlayerConfig = async (accessToken, projectId, branch = "main", instanceUrl) => {
	const baseUrl = instanceUrl || GITLAB_DEFAULT_URL;
	try {
		const response = await fetch(`${baseUrl}/api/v4/projects/${projectId}/repository/tree?ref=${encodeURIComponent(branch)}&recursive=true&per_page=10000`, { headers: {
			Authorization: `Bearer ${accessToken}`,
			Accept: "application/json"
		} });
		if (!response.ok) {
			if (response.status === 404) return [];
			throw new Error(`Failed to fetch repository tree: ${response.statusText}`);
		}
		return (await response.json()).filter((item) => {
			if (item.type !== "blob") return false;
			return configurationFilesCandidates.some((candidate) => item.path.endsWith(candidate));
		}).map((item) => item.path);
	} catch (error) {
		if (error.status === 404) return [];
		logger.error("Error checking intlayer configuration on GitLab:", error);
		return [];
	}
};
/**
* Get repository file contents from GitLab and decode it
*/
const getRepositoryFileContents = async (accessToken, projectId, path, branch = "main", instanceUrl) => {
	const baseUrl = instanceUrl || GITLAB_DEFAULT_URL;
	try {
		const encodedPath = encodeURIComponent(path);
		const response = await fetch(`${baseUrl}/api/v4/projects/${projectId}/repository/files/${encodedPath}/raw?ref=${encodeURIComponent(branch)}`, { headers: {
			Authorization: `Bearer ${accessToken}`,
			Accept: "application/json"
		} });
		if (!response.ok) {
			if (response.status === 404) return null;
			throw new Error(`Failed to fetch file contents: ${response.statusText}`);
		}
		return await response.text();
	} catch (error) {
		if (error.status === 404) return null;
		logger.error("Error fetching GitLab file contents:", error);
		throw error;
	}
};
/**
* Get GitLab access token from user's linked account
*/
const getGitLabTokenFromUser = async (userId) => {
	try {
		const db = getDBClient().db();
		let account = await db.collection("account").findOne({
			userId,
			providerId: "gitlab"
		});
		if (!account && ObjectId.isValid(userId)) account = await db.collection("account").findOne({
			userId: new ObjectId(userId),
			providerId: "gitlab"
		});
		if (!account) account = await db.collection("accounts").findOne({
			userId,
			providerId: "gitlab"
		});
		if (!account && ObjectId.isValid(userId)) account = await db.collection("accounts").findOne({
			userId: new ObjectId(userId),
			providerId: "gitlab"
		});
		if (!account) return null;
		return account.accessToken || account.access_token || null;
	} catch (error) {
		logger.error("Error retrieving GitLab token from DB:", error);
		return null;
	}
};
/**
* Check if a GitLab CI pipeline file exists
*/
const checkPipelineFileExists = async (accessToken, projectId, filename = ".gitlab-ci.yml", branch = "main", instanceUrl) => {
	const baseUrl = instanceUrl || GITLAB_DEFAULT_URL;
	try {
		const encodedPath = encodeURIComponent(filename);
		const response = await fetch(`${baseUrl}/api/v4/projects/${projectId}/repository/files/${encodedPath}?ref=${encodeURIComponent(branch)}`, { headers: {
			Authorization: `Bearer ${accessToken}`,
			Accept: "application/json"
		} });
		if (response.status === 404) return false;
		if (!response.ok) throw new Error(`Failed to check file existence: ${response.statusText}`);
		return true;
	} catch (error) {
		if (error.status === 404) return false;
		logger.error("Error checking pipeline file existence:", error);
		throw error;
	}
};
/**
* Create or update a GitLab CI pipeline file
*/
const createPipelineFile = async (accessToken, projectId, filename = ".gitlab-ci.yml", content, branch = "main", instanceUrl, message = "Add Intlayer CI pipeline") => {
	const baseUrl = instanceUrl || GITLAB_DEFAULT_URL;
	try {
		const encodedPath = encodeURIComponent(filename);
		const encodedContent = Buffer.from(content, "utf-8").toString("base64");
		let existingContentSha;
		try {
			const checkResponse = await fetch(`${baseUrl}/api/v4/projects/${projectId}/repository/files/${encodedPath}?ref=${encodeURIComponent(branch)}`, { headers: {
				Authorization: `Bearer ${accessToken}`,
				Accept: "application/json"
			} });
			if (checkResponse.ok) existingContentSha = (await checkResponse.json()).content_sha256;
		} catch (error) {
			if (error.status !== 404) throw error;
		}
		const body = {
			branch,
			content: encodedContent,
			commit_message: message,
			encoding: "base64"
		};
		if (existingContentSha) body.last_commit_id = existingContentSha;
		const response = await fetch(`${baseUrl}/api/v4/projects/${projectId}/repository/files/${encodedPath}`, {
			method: "PUT",
			headers: {
				Authorization: `Bearer ${accessToken}`,
				"Content-Type": "application/json",
				Accept: "application/json"
			},
			body: JSON.stringify(body)
		});
		if (!response.ok) {
			const errorText = await response.text();
			throw new Error(`Failed to create/update pipeline file: ${errorText}`);
		}
		logger.info(`Successfully ${existingContentSha ? "updated" : "created"} pipeline file ${filename} for project ${projectId}`);
	} catch (error) {
		logger.error("Error creating/updating pipeline file:", error);
		throw error;
	}
};

//#endregion
export { checkIntlayerConfig, checkPipelineFileExists, createPipelineFile, exchangeCodeForToken, getAuthorizationUrl, getGitLabTokenFromUser, getRepositoryFileContents, getUserProjects };
//# sourceMappingURL=gitlab.service.mjs.map