import path             from 'path';
import fs               from 'fs';
import { Exercise }     from '../types/DatabaseTypes.js';
import JSON5            from 'json5';
import GitlabVisibility from '../shared/types/Gitlab/GitlabVisibility.js';


type ConfigGitlabBadge = {
    link: string, imageUrl: string
}


class Config {
    public readonly api: {
        port: number
    };

    public readonly requestClientValidation: {
        version: {
            [client: string]: string
        }
    };

    public readonly dojoCLI: {
        versionUpdatePeriodMs: number
        repositoryId: number
    };

    public readonly jwtConfig: {
        secret: string; expiresIn: number;
    };

    public readonly login: {
        gitlab: {
            client: {
                id: string, secret: string
            }, url: {
                redirect: string, token: string
            }
        }
    };

    public readonly dockerhub: {
        repositories: {
            assignmentChecker: string, exerciseChecker: string
        }
    };

    public readonly gitlab: {
        url: string; urls: Array<string>; repository: {
            timeoutAfterCreation: number;
        }; account: {
            id: number; username: string; token: string;
        }; group: {
            root: number; templates: number; assignments: number; exercises: number; deletedAssignments: number; deletedExercises: number;
        }, badges: {
            pipeline: ConfigGitlabBadge
        }
    };

    public readonly assignment: {
        default: {
            description: string; initReadme: boolean; sharedRunnersEnabled: boolean; visibility: GitlabVisibility; wikiEnabled: boolean; template: string
        }; baseFiles: Array<string>; filename: string
    };

    public readonly exercise: {
        maxSameName: number; maxPerAssignment: number; resultsFolder: string, pipelineResultsFolder: string; default: {
            description: string; visibility: GitlabVisibility;
        };
    };

    constructor() {
        this.api = {
            port: Number(process.env.API_PORT || 30992)
        };

        this.requestClientValidation = JSON5.parse(process.env.REQUEST_CLIENT_VALIDATION || '{"version": {}}');

        this.dojoCLI = {
            versionUpdatePeriodMs: Number(process.env.DOJO_CLI_VERSION_UPDATE_PERIOD_MS || 3600),
            repositoryId         : Number(process.env.DOJO_CLI_GITLAB_REPOSITORY_ID || 0)
        };

        this.jwtConfig = {
            secret   : process.env.JWT_SECRET_KEY || '',
            expiresIn: Number(process.env.SESSION_TIMEOUT || 0)
        };

        this.login = {
            gitlab: {
                client: {
                    id    : process.env.LOGIN_GITLAB_CLIENT_ID || '',
                    secret: process.env.LOGIN_GITLAB_CLIENT_SECRET || ''
                },
                url   : {
                    redirect: process.env.LOGIN_GITLAB_URL_REDIRECT ?? '',
                    token   : process.env.LOGIN_GITLAB_URL_TOKEN ?? ''
                }
            }
        };

        this.dockerhub = {
            repositories: {
                assignmentChecker: process.env.DOCKERHUB_REPO_ASSIGNMENT_CHECKER ?? '',
                exerciseChecker  : process.env.DOCKERHUB_REPO_EXERCISE_CHECKER ?? ''
            }
        };

        this.gitlab = {
            url       : process.env.GITLAB_URL || '',
            urls      : JSON5.parse(process.env.GITLAB_URLS || '[]'),
            account   : {
                id      : Number(process.env.GITLAB_DOJO_ACCOUNT_ID || 0),
                username: process.env.GITLAB_DOJO_ACCOUNT_USERNAME || '',
                token   : process.env.GITLAB_DOJO_ACCOUNT_TOKEN || ''
            },
            repository: {
                timeoutAfterCreation: Number(process.env.GITLAB_REPOSITORY_CREATION_TIMEOUT || 5000)
            },
            group     : {
                root              : Number(process.env.GITLAB_GROUP_ROOT_ID || 0),
                templates         : Number(process.env.GITLAB_GROUP_TEMPLATES_ID || 0),
                assignments       : Number(process.env.GITLAB_GROUP_ASSIGNMENTS_ID || 0),
                exercises         : Number(process.env.GITLAB_GROUP_EXERCISES_ID || 0),
                deletedAssignments: Number(process.env.GITLAB_GROUP_DELETED_ASSIGNMENTS_ID || 0),
                deletedExercises  : Number(process.env.GITLAB_GROUP_DELETED_EXERCISES_ID || 0)
            },
            badges    : {
                pipeline: {
                    link    : process.env.GITLAB_BADGE_PIPELINE_LINK || '',
                    imageUrl: process.env.GITLAB_BADGE_PIPELINE_IMAGE_URL || ''
                }
            }
        };

        this.assignment = {
            default  : {
                description         : process.env.ASSIGNMENT_DEFAULT_DESCRIPTION?.convertWithEnvVars() ?? '',
                initReadme          : process.env.ASSIGNMENT_DEFAULT_INIT_README?.toBoolean() ?? false,
                sharedRunnersEnabled: process.env.ASSIGNMENT_DEFAULT_SHARED_RUNNERS_ENABLED?.toBoolean() ?? true,
                visibility          : process.env.ASSIGNMENT_DEFAULT_VISIBILITY as GitlabVisibility || 'private',
                wikiEnabled         : process.env.ASSIGNMENT_DEFAULT_WIKI_ENABLED?.toBoolean() ?? false,
                template            : process.env.ASSIGNMENT_DEFAULT_TEMPLATE?.replace('{{USERNAME}}', this.gitlab.account.username).replace('{{TOKEN}}', this.gitlab.account.token) ?? ''
            },
            baseFiles: JSON5.parse(process.env.ASSIGNMENT_BASE_FILES || '[]'),
            filename : process.env.ASSIGNMENT_FILENAME || ''
        };

        this.exercise = {
            maxSameName          : Number(process.env.EXERCISE_MAX_SAME_NAME || 0),
            maxPerAssignment     : Number(process.env.EXERCISE_MAX_PER_ASSIGNMENT || 2),
            resultsFolder        : process.env.EXERCISE_RESULTS_FOLDER?.convertWithEnvVars() ?? '',
            pipelineResultsFolder: process.env.EXERCISE_PIPELINE_RESULTS_FOLDER ?? '', //Do not use convertWithEnvVars() because it is used in the exercise creation and muste be interpreted at exercise runtime
            default              : {
                description: process.env.EXERCISE_DEFAULT_DESCRIPTION?.convertWithEnvVars() ?? '',
                visibility : process.env.EXERCISE_DEFAULT_VISIBILITY as GitlabVisibility || 'private'
            }
        };
    }

    public getResultsFolder(exercise: Exercise): string {
        const folderPath = path.join(this.exercise.resultsFolder, exercise.assignmentName, exercise.id);

        fs.mkdirSync(folderPath, { recursive: true });

        return folderPath;
    }
}


export default new Config();