import axios, { AxiosError } from 'axios';
import Config                from '../config/Config';
import ora                   from 'ora';
import ApiRoutes             from '../sharedByClients/types/ApiRoutes';
import { StatusCodes }       from 'http-status-codes';
import Enonce                from '../sharedByClients/models/Enonce';
import GitlabUser            from '../shared/types/Gitlab/GitlabUser';
import Exercice              from '../sharedByClients/models/Exercice';
import DojoResponse          from '../shared/types/DojoResponse';


class DojoBackendManager {
    public getApiUrl(route: ApiRoutes): string {
        return `${ Config.apiURL }${ route }`;
    }

    public async getEnonce(nameOrUrl: string): Promise<Enonce | undefined> {
        try {
            return (await axios.get<DojoResponse<Enonce>>(this.getApiUrl(ApiRoutes.ENONCE_GET).replace('{{nameOrUrl}}', encodeURIComponent(nameOrUrl)))).data.data;
        } catch ( error ) {
            return undefined;
        }
    }


    public async checkTemplateAccess(idOrNamespace: string, verbose: boolean = true): Promise<boolean> {
        const spinner: ora.Ora = ora('Checking template access');

        if ( verbose ) {
            spinner.start();
        }

        try {
            await axios.get(this.getApiUrl(ApiRoutes.GITLAB_CHECK_TEMPLATE_ACCESS).replace('{{id}}', idOrNamespace));

            if ( verbose ) {
                spinner.succeed('Template access granted');
            }

            return true;
        } catch ( error ) {
            if ( verbose ) {
                if ( error instanceof AxiosError ) {
                    if ( error.response ) {
                        if ( error.response.status === StatusCodes.NOT_FOUND ) {
                            spinner.fail(`Template not found or access denied. Please check the template ID or url. Also, please check that the template have public/internal visibility or that your and Dojo account (${ Config.gitlab.dojoAccount.username }) have at least reporter role to the template (if private).`);
                        } else if ( error.response.status === StatusCodes.UNAUTHORIZED ) {
                            spinner.fail(`Please check that the template have public/internal visibility or that your and Dojo account (${ Config.gitlab.dojoAccount.username }) have at least reporter role to the template (if private).`);
                        } else {
                            spinner.fail(`Template error: ${ error.response.statusText }`);
                        }
                    }
                } else {
                    spinner.fail(`Template error: ${ error }`);
                }
            }

            return false;
        }
    }

    public async createEnonce(name: string, members: Array<GitlabUser>, templateIdOrNamespace: string | null, verbose: boolean = true): Promise<Enonce> {
        const spinner: ora.Ora = ora('Creating enonce...');

        if ( verbose ) {
            spinner.start();
        }

        try {
            const response = await axios.post<DojoResponse<Enonce>>(this.getApiUrl(ApiRoutes.ENONCE_CREATE), Object.assign({
                                                                                                                               name   : name,
                                                                                                                               members: JSON.stringify(members)
                                                                                                                           }, templateIdOrNamespace ? { template: templateIdOrNamespace } : {}));

            if ( verbose ) {
                spinner.succeed(`Enonce successfully created`);
            }

            return response.data.data;
        } catch ( error ) {
            if ( verbose ) {
                if ( error instanceof AxiosError ) {
                    if ( error.response ) {
                        if ( error.response.status === StatusCodes.CONFLICT ) {
                            spinner.fail(`The enonce name is already used. Please choose another one.`);
                        } else {
                            spinner.fail(`Enonce creation error: ${ error.response.statusText }`);
                        }
                    }
                } else {
                    spinner.fail(`Enonce creation error: unknown error`);
                }
            }

            throw error;
        }
    }

    public async createExercice(enonceName: string, members: Array<GitlabUser>, verbose: boolean = true): Promise<Exercice> {
        const spinner: ora.Ora = ora('Creating exercice...');

        if ( verbose ) {
            spinner.start();
        }

        try {
            const response = await axios.post<DojoResponse<Exercice>>(this.getApiUrl(ApiRoutes.EXERCICE_CREATE).replace('{{nameOrUrl}}', encodeURIComponent(enonceName)), { members: JSON.stringify(members) });

            if ( verbose ) {
                spinner.succeed(`Exercice successfully created`);
            }

            return response.data.data;
        } catch ( error ) {
            if ( verbose ) {
                if ( error instanceof AxiosError ) {
                    if ( error.response ) {
                        if ( error.response.status === StatusCodes.CONFLICT ) {
                            spinner.fail(`You've reached the max number of exercice of this enonce.`);
                        } else {
                            spinner.fail(`Exercice creation error: ${ error.response.statusText }`);
                        }
                    }
                } else {
                    spinner.fail(`Exercice creation error: unknown error`);
                }
            }

            throw error;
        }
    }

    public async changeEnoncePublishedStatus(enonce: Enonce, publish: boolean, verbose: boolean = true) {
        const spinner: ora.Ora = ora('Changing published status...');

        if ( verbose ) {
            spinner.start();
        }

        try {
            await axios.patch<DojoResponse<null>>(this.getApiUrl(publish ? ApiRoutes.ENONCE_PUBLISH : ApiRoutes.ENONCE_UNPUBLISH).replace('{{nameOrUrl}}', encodeURIComponent(enonce.name)), {});

            if ( verbose ) {
                spinner.succeed(`Enonce ${ enonce.name } successfully ${ publish ? 'published' : 'unpublished' }`);
            }

            return;
        } catch ( error ) {
            if ( verbose ) {
                if ( error instanceof AxiosError && error.response ) {
                    spinner.fail(`Enonce visibility change error: ${ error.response.statusText }`);
                } else {
                    spinner.fail(`Enonce visibility change error: unknown error`);
                }
            }

            throw error;
        }
    }
}


export default new DojoBackendManager();