#pragma once

#include "commands.h"

namespace NSaasLB {
    class ICommandParser {
    public:
        using TPtr = TAtomicSharedPtr<ICommandParser>;

    public:
        virtual ~ICommandParser() = default;
        virtual ICommand::TPtr Parse(int index, int argc, char* argv[]) const = 0;

        virtual void AddParserChild(TVector<TString>::iterator begin, TVector<TString>::iterator end, ICommandParser::TPtr);

    public:
        virtual void PrintChildsCommands(const TString& outputLinePrefix) const = 0;
    };

    class TMultiCommandParser : public ICommandParser {
    public:
        ICommand::TPtr Parse(int index, int argc, char* argv[]) const override;

        void PrintHelp(const TString& commandLine, const TString& error = "") const;

        void AddParserChild(TVector<TString>::iterator begin, TVector<TString>::iterator end, ICommandParser::TPtr parser) override;

    protected:
        void PrintChildsCommands(const TString& outputLinePrefix) const override;

    protected:
        THashMap<TString, ICommandParser::TPtr> Childs;
    };

    template <class TCommand>
    class TFinalCommandParser : public ICommandParser {
    public:
        using TOptions = typename TCommand::TOptionsType;

    public:
        ICommand::TPtr Parse(int index, int argc, char* argv[]) const override;
        void PrintHelp(const TOptions& options, const TString& commandLine, const TString& error = "") const;

    protected:
        void PrintChildsCommands(const TString&) const override {};
    };

    class TMainCommandParser : public TMultiCommandParser {
    public:
        TMainCommandParser();

    private:
        void Init();

        template<class TCommand>
        void AddCommand(const TString& commandLine) {
            auto path = SplitString(commandLine, " ");
            AddParserChild(path.begin(), path.end(), MakeAtomicShared<TFinalCommandParser<TCommand>>());
        }
    };
}
