var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
import { BaseGitProviderClient } from "./BaseGitProviderClient";
import { WorkspaceBackendError } from "./errors";
import { parseGitRemote } from "./gitRemote";
function inferApiBase(config, host) {
    const configured = config.apiBaseUrl;
    if (configured === null || configured === void 0 ? void 0 : configured.trim())
        return configured.trim().replace(/\/+$/g, "");
    return `https://${host}/api/v1`;
}
function parseOwnerRepo(remoteUrl) {
    const { host, repoPath } = parseGitRemote(remoteUrl);
    const parts = repoPath.split("/").filter(Boolean);
    if (parts.length < 2)
        throw new Error("Invalid git remote URL");
    const owner = parts[0];
    const repo = parts[1];
    return { owner, repo, host };
}
export class GiteaProviderClient extends BaseGitProviderClient {
    static canHandle(config) {
        const provider = config.provider;
        if (provider && provider !== "auto")
            return provider === "gitea";
        try {
            const { host } = parseGitRemote(config.remoteUrl);
            return host.includes("gitea");
        }
        catch (_a) {
            return false;
        }
    }
    request(apiBase, config, path, init) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            const headers = {
                Accept: "application/json",
            };
            const token = (_a = config.auth.token) === null || _a === void 0 ? void 0 : _a.trim();
            if (token)
                headers.Authorization = `token ${token}`;
            const res = yield fetch(`${apiBase}${path}`, Object.assign(Object.assign({}, init), { cache: "no-store", headers: Object.assign(Object.assign({}, headers), init === null || init === void 0 ? void 0 : init.headers) }));
            const status = res.status;
            const contentType = res.headers.get("content-type") || "";
            if (contentType.includes("application/json")) {
                const text = yield res.text();
                if (text.trim()) {
                    try {
                        const json = JSON.parse(text);
                        return { status, json };
                    }
                    catch (_b) {
                        return { status };
                    }
                }
                return { status };
            }
            const text = yield res.text();
            return { status, text };
        });
    }
    validateAccess(config) {
        return __awaiter(this, void 0, void 0, function* () {
            const { owner, repo, host } = parseOwnerRepo(config.remoteUrl);
            const apiBase = inferApiBase(config, host);
            const { status } = yield this.request(apiBase, config, `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`);
            this.ensureOk(status, "Could not access repository with the provided token.");
        });
    }
    listFolder(config, folderId) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            const { owner, repo, host } = parseOwnerRepo(config.remoteUrl);
            const apiBase = inferApiBase(config, host);
            const relPath = (folderId === null || folderId === void 0 ? void 0 : folderId.trim()) || "";
            const fullPath = this.joinPath(config.rootPath, relPath);
            const pathPart = fullPath ? `/${this.encodePath(fullPath)}` : "";
            const ref = ((_a = config.branch) === null || _a === void 0 ? void 0 : _a.trim()) ? `?ref=${encodeURIComponent(config.branch.trim())}` : "";
            const { status, json } = yield this.request(apiBase, config, `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/contents${pathPart}${ref}`);
            if (status === 404)
                return [];
            this.ensureOk(status, "Failed to list folder contents.");
            const items = Array.isArray(json) ? json : [];
            const entries = [];
            for (const item of items) {
                if (item.type === "dir") {
                    const id = relPath ? this.joinPath(relPath, item.name) : item.name;
                    entries.push({ kind: "folder", id, label: item.name, parentId: relPath || undefined });
                    continue;
                }
                if (item.type === "file") {
                    if (!/\.sparql$/i.test(item.name))
                        continue;
                    const id = relPath ? this.joinPath(relPath, item.name) : item.name;
                    const label = item.name.replace(/\.sparql$/i, "");
                    entries.push({ kind: "query", id, label, parentId: relPath || undefined });
                }
            }
            entries.sort((a, b) => {
                if (a.kind !== b.kind)
                    return a.kind === "folder" ? -1 : 1;
                return a.label.toLowerCase().localeCompare(b.label.toLowerCase());
            });
            return entries;
        });
    }
    readFileAtRef(config, apiBase, owner, repo, queryId, ref) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            const filePath = this.joinPath(config.rootPath, queryId);
            const refQ = ref
                ? `?ref=${encodeURIComponent(ref)}`
                : ((_a = config.branch) === null || _a === void 0 ? void 0 : _a.trim())
                    ? `?ref=${encodeURIComponent(config.branch.trim())}`
                    : "";
            const { status, json } = yield this.request(apiBase, config, `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/contents/${this.encodePath(filePath)}${refQ}`);
            this.ensureOk(status, "Failed to read query.");
            const content = (json === null || json === void 0 ? void 0 : json.content) || "";
            const text = (json === null || json === void 0 ? void 0 : json.encoding) === "base64" ? this.base64DecodeUtf8(content) : content;
            return { text, sha: json === null || json === void 0 ? void 0 : json.sha };
        });
    }
    readQuery(config, queryId) {
        return __awaiter(this, void 0, void 0, function* () {
            const { owner, repo, host } = parseOwnerRepo(config.remoteUrl);
            const apiBase = inferApiBase(config, host);
            const { text, sha } = yield this.readFileAtRef(config, apiBase, owner, repo, queryId);
            return { queryText: text, versionTag: sha };
        });
    }
    writeQuery(config, queryId, queryText, options) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            const { owner, repo, host } = parseOwnerRepo(config.remoteUrl);
            const apiBase = inferApiBase(config, host);
            const filePath = this.joinPath(config.rootPath, queryId);
            let currentSha;
            try {
                const res = yield this.readFileAtRef(config, apiBase, owner, repo, queryId);
                currentSha = res.sha;
            }
            catch (e) {
                const err = e;
                if ((err === null || err === void 0 ? void 0 : err.code) !== "NOT_FOUND")
                    throw e;
            }
            if ((options === null || options === void 0 ? void 0 : options.expectedVersionTag) && currentSha && options.expectedVersionTag !== currentSha) {
                throw new WorkspaceBackendError("CONFLICT", "The file changed remotely since it was last opened. Please reload the managed query and try saving again.");
            }
            const message = this.getCommitMessage(queryId, options, !currentSha);
            const body = {
                message,
                content: this.base64EncodeUtf8(queryText),
            };
            if ((_a = config.branch) === null || _a === void 0 ? void 0 : _a.trim())
                body.branch = config.branch.trim();
            if (currentSha)
                body.sha = currentSha;
            const { status } = yield this.request(apiBase, config, `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/contents/${this.encodePath(filePath)}`, {
                method: "PUT",
                body: JSON.stringify(body),
                headers: { "Content-Type": "application/json" },
            });
            this.ensureOk(status, "Failed to save query to Gitea workspace.");
        });
    }
    listVersions(config, queryId) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            const { owner, repo, host } = parseOwnerRepo(config.remoteUrl);
            const apiBase = inferApiBase(config, host);
            const filePath = this.joinPath(config.rootPath, queryId);
            const qs = new URLSearchParams();
            if ((_a = config.branch) === null || _a === void 0 ? void 0 : _a.trim())
                qs.set("sha", config.branch.trim());
            qs.set("path", filePath);
            qs.set("limit", "30");
            const { status, json } = yield this.request(apiBase, config, `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/commits?${qs.toString()}`);
            this.ensureOk(status, "Failed to list query versions.");
            const commits = Array.isArray(json) ? json : [];
            return commits
                .map((c) => {
                var _a, _b, _c, _d, _e, _f, _g, _h;
                const createdAt = c.created || ((_b = (_a = c.commit) === null || _a === void 0 ? void 0 : _a.committer) === null || _b === void 0 ? void 0 : _b.date) || ((_d = (_c = c.commit) === null || _c === void 0 ? void 0 : _c.author) === null || _d === void 0 ? void 0 : _d.date) || new Date().toISOString();
                const author = ((_e = c.author) === null || _e === void 0 ? void 0 : _e.login) || ((_g = (_f = c.commit) === null || _f === void 0 ? void 0 : _f.author) === null || _g === void 0 ? void 0 : _g.name);
                const message = ((_h = c.commit) === null || _h === void 0 ? void 0 : _h.message) || "";
                return { id: c.sha, createdAt, author, message };
            })
                .filter((v) => !!v.id);
        });
    }
    readVersion(config, queryId, versionId) {
        return __awaiter(this, void 0, void 0, function* () {
            const { owner, repo, host } = parseOwnerRepo(config.remoteUrl);
            const apiBase = inferApiBase(config, host);
            const { text, sha } = yield this.readFileAtRef(config, apiBase, owner, repo, queryId, versionId);
            return { queryText: text, versionTag: sha };
        });
    }
    deleteQuery(config, queryId) {
        return __awaiter(this, void 0, void 0, function* () {
            var _a;
            const { owner, repo, host } = parseOwnerRepo(config.remoteUrl);
            const apiBase = inferApiBase(config, host);
            const filePath = this.joinPath(config.rootPath, queryId);
            let currentSha;
            try {
                const res = yield this.readFileAtRef(config, apiBase, owner, repo, queryId);
                currentSha = res.sha;
            }
            catch (e) {
                const err = e;
                if ((err === null || err === void 0 ? void 0 : err.code) === "NOT_FOUND")
                    return;
                throw e;
            }
            if (!currentSha)
                return;
            const body = {
                message: this.getDeleteMessage(queryId),
                sha: currentSha,
            };
            if ((_a = config.branch) === null || _a === void 0 ? void 0 : _a.trim())
                body.branch = config.branch.trim();
            const { status } = yield this.request(apiBase, config, `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/contents/${this.encodePath(filePath)}`, {
                method: "DELETE",
                body: JSON.stringify(body),
                headers: { "Content-Type": "application/json" },
            });
            if (status === 404)
                return;
            this.ensureOk(status, "Failed to delete query.");
        });
    }
}
//# sourceMappingURL=GiteaProviderClient.js.map