import { Command, Option } from 'commander';
import ClientsSharedConfig from '../sharedByClients/config/ClientsSharedConfig.js';
import AssignmentCommand   from './assignment/AssignmentCommand.js';
import ExerciseCommand     from './exercise/ExerciseCommand.js';
import SharedConfig        from '../shared/config/SharedConfig.js';
import boxen               from 'boxen';
import { stateConfigFile } from '../config/ConfigFiles.js';
import semver              from 'semver/preload.js';
import { version }         from '../config/Version.js';
import Config              from '../config/Config.js';
import CompletionCommand   from './completion/CompletionCommand.js';
import AuthCommand         from './auth/AuthCommand.js';
import SessionCommand      from './auth/SessionCommand.js';
import UpgradeCommand      from './UpgradeCommand.js';
import TextStyle           from '../types/TextStyle.js';


class CommanderApp {
    public program: Command = new Command();

    private readonly commandHookDisabled: Array<string> = [ 'completion' ];

    private hasToExecuteHook(actionCommand: Command): boolean {
        if ( actionCommand.parent == null ) {
            return true;
        } else {
            if ( this.commandHookDisabled.includes(actionCommand.name()) ) {
                return false;
            }

            return this.hasToExecuteHook(actionCommand.parent);
        }
    }

    constructor() {
        this.program
            .name('dojo')
            .description('CLI of the Dojo application')
            .version('{{VERSION}}')
            .showHelpAfterError()
            .configureHelp({
                               showGlobalOptions: true,
                               sortOptions      : true,
                               sortSubcommands  : true
                           })
            .option('-H, --host <string>', 'override the Dojo API endpoint', ClientsSharedConfig.apiURL)
            .option('-I, --interactive', 'show interactive interface when available', Config.interactiveMode)
            .addOption(new Option('--debug').hideHelp())
            .hook('preAction', (_thisCommand: Command, actionCommand: Command) => {
                if ( this.hasToExecuteHook(actionCommand) ) {
                    this.warnDevelopmentVersion();
                }
            })
            .hook('postAction', (_thisCommand: Command, actionCommand: Command) => {
                if ( this.hasToExecuteHook(actionCommand) ) {
                    this.informNewVersion();
                }
            });

        this.program.on('option:host', () => {
            ClientsSharedConfig.apiURL = this.program.opts().host;
        });

        this.program.on('option:interactive', () => {
            Config.interactiveMode = this.program.opts().interactive;
        });

        this.program.on('option:debug', () => {
            SharedConfig.debug = true;
        });

        this.registerCommands();
    }

    public parse() {
        this.program.parse();
    }

    private warnDevelopmentVersion() {
        if ( !SharedConfig.production ) {
            console.log(boxen(`This is a development (unstable) version of the DojoCLI.
If you want to use the stable version, please execute this command: 
${ TextStyle.CODE(' dojo upgrade ') }`, {
                title         : 'Warning',
                titleAlignment: 'center',
                borderColor   : 'red',
                borderStyle   : 'bold',
                margin        : 1,
                padding       : 1,
                textAlignment : 'left'
            }));
        }
    }

    private informNewVersion() {
        if ( SharedConfig.production ) {
            const latestDojoCliVersion = stateConfigFile.getParam('latestDojoCliVersion') as string | null || '0.0.0';
            const latestDojoCliVersionNotification = stateConfigFile.getParam('latestDojoCliVersionNotification') as number | null || 0;
            if ( semver.lt(version, latestDojoCliVersion) && (new Date()).getTime() - latestDojoCliVersionNotification >= Config.versionUpdateInformationPeriodHours * 60 * 60 * 1000 ) {
                console.log(boxen(`The ${ latestDojoCliVersion } version of the DojoCLI is available.
You can upgrade the DojoCLI by executing this command: 
${ TextStyle.CODE(' dojo upgrade ') }`, {
                    title         : 'Information',
                    titleAlignment: 'center',
                    borderColor   : 'blue',
                    borderStyle   : 'bold',
                    margin        : 1,
                    padding       : 1,
                    textAlignment : 'left'
                }));
                stateConfigFile.setParam('latestDojoCliVersionNotification', (new Date()).getTime());
            }
        }
    }

    private registerCommands() {
        new AuthCommand().registerOnCommand(this.program);
        SessionCommand.registerOnCommand(this.program);
        AssignmentCommand.registerOnCommand(this.program);
        ExerciseCommand.registerOnCommand(this.program);
        CompletionCommand.registerOnCommand(this.program);
        UpgradeCommand.registerOnCommand(this.program);
    }
}


export default CommanderApp;