#include "sender.h"
#include "broadcast.h"
#include <saas/util/external/dc.h>
#include <library/cpp/logger/global/global.h>

namespace NRTYDeploy {

    namespace {
        class TParserActor: public IObjectInQueue {
        private:
            TBroadcastSender& Sender;
            const TBroadcastSlotData& SlotData;
            const TString Reply;
        public:

            TParserActor(TBroadcastSender& sender, const TBroadcastSlotData& slotData, const TString& reply)
                : Sender(sender)
                , SlotData(slotData)
                , Reply(reply)
            {

            }

            void Process(void* /*threadSpecificResource*/) override {
                Sender.GetScript().AddReplyInfo(SlotData, Reply);
            }
        };

        class TWaitPolicy: public NScatter::IWaitPolicy
        {
            bool IsAccepted(const NScatter::ITask& /*task*/) final {
                return true;
            }
        };

        class TRequest: public NScatter::ITask {
        private:
            TBroadcastSender& Sender;
        protected:
            void FillRequestData(NScatter::TRequestData& rd) const override {
                rd.Url = Sender.GetScript().GetCommand();
            }

            void DoHandleError(const NScatter::TErrorDetails& details) override {
                ERROR_LOG << details.Connection.SearchScript() << ": " << details.ErrorMessage << Endl;
                Sender.AddReply(details.Connection.SearchScript(), details.ErrorMessage);
            }

            NScatter::TParseResult DoParse(const NScatter::TTaskReply& reply) override {
                INFO_LOG << reply.Connection->SearchScript() << ": OK" << Endl;
                if (reply.Connection) {
                    Sender.AddReply(reply.Connection->SearchScript(), reply.Data);
                }
                return NScatter::TParseResult(NScatter::ITask::Finished);
            }

        public:
            TRequest(TBroadcastSender& sender, NScatter::ISource& source)
                : NScatter::ITask(source)
                , Sender(sender)
            {

            }

            size_t GetParallelRequestCount() const override {
                return 2;
            }

        };
    }

    void TBroadcastSender::AddReply(const TString& searchScript, const TString& reply) {
        auto it = SlotsData.find(searchScript);
        CHECK_WITH_LOG(it != SlotsData.end());
        Script.RunAsync(new TParserActor(*this, it->second, reply));
    }

    void TBroadcastSender::Wait() {
        NScatter::IWaitPolicyRef waitPolicy = new TWaitPolicy();
        waitPolicy->WaitOptions.TasksCheckInterval = TDuration::MilliSeconds(50);
        Requester.Wait("", waitPolicy);
    }

    void TBroadcastSender::AddSource(const TBroadcastSlotData& slotData) {
        TString host = TDatacenterUtil::Instance().GetPodIP(slotData.SMHost.Name);
        if (host == "") {
            host = slotData.SMHost.Name;
        } else {
            host = "[" + host + "]";
        }
        TString script = "http://" + host + ":" + ToString(slotData.SMHost.ControllerPort()) + "/";

        SlotsData[script + "?"] = slotData;
        try {
            Sources[slotData] = NScatter::CreateSimpleSource(script + " " + script + " " + script, Opts);
            NScatter::ITaskRef task = new TRequest(*this, *Sources[slotData]);
            Requester.Schedule(task);
        } catch (...) {
            Script.RunAsync(new TParserActor(*this, SlotsData[script + "?"], CurrentExceptionMessage()));
        }
    }

}
