import express                   from 'express';
import logger                    from '../shared/logging/WinstonLogger.js';
import GitlabManager             from '../managers/GitlabManager.js';
import DojoStatusCode            from '../shared/types/Dojo/DojoStatusCode.js';
import { StatusCodes }           from 'http-status-codes';
import { GitbeakerRequestError } from '@gitbeaker/requester-utils';
import * as Gitlab               from '@gitbeaker/rest';
import axios, { AxiosError } from 'axios';
import SharedConfig     from '../shared/config/SharedConfig';


class GlobalHelper {
    repoCreationFnExecCreator(req: express.Request, res: express.Response, gitlabError: DojoStatusCode, internalError: DojoStatusCode, repositoryToRemove?: Gitlab.ProjectSchema) {
        return async (toExec: () => Promise<unknown>, errorMessage?: string) => {
            try {
                return await toExec();
            } catch ( error ) {
                if ( errorMessage ) {
                    logger.error(errorMessage);
                    logger.error(JSON.stringify(error));

                    try {
                        if ( repositoryToRemove ) {
                            await GitlabManager.deleteRepository(repositoryToRemove.id);
                        }
                    } catch ( deleteError ) {
                        logger.error('Repository deletion error');
                        logger.error(JSON.stringify(deleteError));
                    }

                    if ( error instanceof GitbeakerRequestError ) {
                        req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, `Unknown gitlab error: ${ errorMessage }`, gitlabError);
                        throw error;
                    }

                    req.session.sendResponse(res, StatusCodes.INTERNAL_SERVER_ERROR, {}, `Unknown error: ${ errorMessage }`, internalError);
                    throw error;
                }
            }

            return undefined;
        };
    }

    isRepoNameAlreadyTaken(errorDescription: unknown) {
        return errorDescription instanceof Array && errorDescription.length > 0 && (errorDescription[0] as string).includes('has already been taken');
    }

    addRepoMember(repositoryId: number) {
        return async (memberId: number): Promise<Gitlab.MemberSchema | false> => {
            try {
                return await GitlabManager.addRepositoryMember(repositoryId, memberId, Gitlab.AccessLevel.DEVELOPER);
            } catch ( error ) {
                logger.error('Add member error');
                logger.error(JSON.stringify(error));
                return false;
            }
        };
    }

    async isSonarSupported(): Promise<boolean> {
        try {
            const sonar = await axios.get(SharedConfig.sonar.url);
            return SharedConfig.sonar.enabled && sonar.status == 200;
        } catch ( error ) {
            return false;
        }
    }
}


export default new GlobalHelper();