import CommanderCommand   from '../../CommanderCommand';
import ora                from 'ora';
import DojoBackendManager from '../../../managers/DojoBackendManager';
import AccessesHelper     from '../../../helpers/AccessesHelper';
import Assignment         from '../../../sharedByClients/models/Assignment';
import Exercise           from '../../../sharedByClients/models/Exercise';
import * as Gitlab        from '@gitbeaker/rest';
import TextStyle          from '../../../types/TextStyle';
import GitlabManager      from '../../../managers/GitlabManager';


type CommandOptions = { assignment: string, members_id?: Array<number>, members_username?: Array<string>, clone?: string | boolean }


class ExerciseCreateCommand extends CommanderCommand {
    protected commandName: string = 'create';

    private members!: Array<Gitlab.UserSchema> | undefined;
    private assignment!: Assignment | undefined;
    private exercise!: Exercise;

    protected defineCommand() {
        this.command
            .description('create a new exercise from an assignment')
            .requiredOption('-a, --assignment <value>', 'assignment source (Dojo assignment ID, Dojo assignment name or Gitlab assignment URL)')
            .option('-i, --members_id <ids...>', 'list of gitlab members ids (group\'s student) to add to the repository')
            .option('-u, --members_username <usernames...>', 'list of gitlab members username (group\'s student) to add to the repository')
            .option('-c, --clone [string]', 'automatically clone the repository (SSH required) in the specified directory (this will create a subdirectory with the assignment name)')
            .action(this.commandAction.bind(this));
    }

    private async dataRetrieval(options: CommandOptions) {
        console.log(TextStyle.BLOCK('Please wait while we verify and retrieve data...'));

        if ( !await AccessesHelper.checkStudent() ) {
            throw new Error();
        }

        this.members = await GitlabManager.fetchMembers(options);
        if ( !this.members ) {
            throw new Error();
        }

        ora('Checking assignment:').start().info();
        const assignmentGetSpinner: ora.Ora = ora({
                                                      text  : 'Checking if assignment exists',
                                                      indent: 4
                                                  }).start();
        this.assignment = await DojoBackendManager.getAssignment(options.assignment);
        if ( !this.assignment ) {
            assignmentGetSpinner.fail(`Assignment "${ options.assignment }" doesn't exists`);
            throw new Error();
        }
        assignmentGetSpinner.succeed(`Assignment "${ options.assignment }" exists`);

        const assignmentPublishedSpinner: ora.Ora = ora({
                                                            text  : 'Checking if assignment is published',
                                                            indent: 4
                                                        }).start();
        if ( !this.assignment.published ) {
            assignmentPublishedSpinner.fail(`Assignment "${ this.assignment.name }" isn't published`);
            throw new Error();
        }
        assignmentPublishedSpinner.succeed(`Assignment "${ this.assignment.name }" is published`);
    }

    private async createExercise() {
        console.log(TextStyle.BLOCK('Please wait while we are creating the exercise (approximately 10 seconds)...'));

        this.exercise = await DojoBackendManager.createExercise(this.assignment!.name, this.members!);

        const oraInfo = (message: string) => {
            ora({
                    text  : message,
                    indent: 4
                }).start().info();
        };

        oraInfo(`${ TextStyle.LIST_ITEM_NAME('Id:') } ${ this.exercise.id }`);
        oraInfo(`${ TextStyle.LIST_ITEM_NAME('Name:') } ${ this.exercise.name }`);
        oraInfo(`${ TextStyle.LIST_ITEM_NAME('Web URL:') } ${ this.exercise.gitlabCreationInfo.web_url }`);
        oraInfo(`${ TextStyle.LIST_ITEM_NAME('HTTP Repo:') } ${ this.exercise.gitlabCreationInfo.http_url_to_repo }`);
        oraInfo(`${ TextStyle.LIST_ITEM_NAME('SSH Repo:') } ${ this.exercise.gitlabCreationInfo.ssh_url_to_repo }`);
    }

    private async cloneRepository(options: CommandOptions) {
        if ( options.clone ) {
            console.log(TextStyle.BLOCK('Please wait while we are cloning the repository...'));

            await GitlabManager.cloneRepository(options.clone, this.exercise.gitlabCreationInfo.ssh_url_to_repo, `DojoExercise_${ this.exercise.assignmentName }`, true, 0);
        }
    }


    protected async commandAction(options: CommandOptions): Promise<void> {
        try {
            await this.dataRetrieval(options);
            await this.createExercise();
            await this.cloneRepository(options);
        } catch ( e ) { /* Do nothing */ }
    }
}


export default new ExerciseCreateCommand();