/******************************************************************************
*	File		-	console.h
*	Author		-	Joey Pollack
*	Date		-	2022/02/09 (y/m/d)
*	Mod Date	-	2022/02/09 (y/m/d)
*	Description	-	Engine console for viewing the debug log and entering lua
                    commands
******************************************************************************/

#include "console.h"
#include <dearimgui/imgui.h>
#include <core/core.h>
#include <input/input_manager.h>
#include <cstring>
#include <sstream>
#include <iostream>
namespace lunarium
{
    namespace gui
    {
    ////////////////////////////////////////////////////////////
    //				GUI LOG LISTENER
    ////////////////////////////////////////////////////////////
    GuiListener::GuiListener(Console* pGui, uint32_t acceptedLogLevels, uint32_t acceptedLogCategories, const char* myName)
        : LogListener(acceptedLogLevels, acceptedLogCategories, myName), mpConsole(pGui)
    {

    }

	bool GuiListener::Log(LogMessage& message)
    {
        if (!LevelIsSet(message.LogLevel) ||
			!CategoryIsSet(message.LogCategory))
			return false;

        std::ostringstream oss;

		oss << std::endl << Logger::TimeStamp() << Logger::GetCategoryName(message.LogCategory)
					<< Logger::GetLevelName(message.LogLevel) << message.Message << std::flush;
        
        mpConsole->mMsgHistory.push_back(oss.str());
		return true;
    }

    ////////////////////////////////////////////////////////////
    //				CONSOLE
    ////////////////////////////////////////////////////////////
    Console::Console(const char* name)
        : Panel(name, gui::PanelDockZone::DDZ_NONE, false),
            mbNewCommand(false), mRecalledCommand(-1), mIsFocused(false), mListener(nullptr),
            mbOglDebug(false), mbInfoVerbose(false), mpListener(nullptr)
    {
        memset(mBuffer, 0, LUA_CON_BUFFER_SIZE);
        mpListener = Logger::GetInstance()->AddListener(new GuiListener(this));
    }

    Console::~Console()
    {
        Logger::GetInstance()->RemoveListener(mpListener);
        delete mpListener;
        mpListener = nullptr;
    }


    bool Console::IsFocused() const
    {
        return mIsFocused;
    }
    
    void Console::Update(float dt)
    {

    }

    bool Console::DoFrame()
    {

        if (Core::Input().IsKeyDown(KeyCode::ESCAPE, true))
        {
            mRecalledCommand = -1;
        }




        float history_height = ImGui::GetWindowSize().y - 45;
        ImGui::BeginChild("history", ImVec2(0, history_height), false, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_NoMove);
        mIsFocused = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows);
        // for (int i = 0; i < mCommandHistory.size(); i++)
        // {
        //     const char* msg = mCommandHistory[i].c_str();
        //     int len = strlen(msg);

        //     if (i == mRecalledCommand)
        //     {
        //         ImGui::TextColored(ImVec4(0.2f, 0.9f, 0.5f, 1.0f), msg);
        //     }
        //     else
        //     {
        //         ImGui::TextUnformatted(msg);
        //     }
        // }

         for (int i = 0; i < mMsgHistory.size(); i++)
        {
            if ((mMsgHistory[i].find("[GRAPHICS_INTERNAL_DEBUG]") != std::string::npos && !mbOglDebug)
            || (mMsgHistory[i].find("[TRACE]") != std::string::npos && !mbInfoVerbose))
            {
                continue;
            }

            ImVec4 color(1.0f, 1.0f, 1.0f, 1.0f);


            if (mMsgHistory[i].find("[LUA]") != std::string::npos)
            {
                color = ImVec4(0.25f, 0.5f, 0.95f, 1.0f);
            }
            
            if (mMsgHistory[i].find("WARNING") != std::string::npos)
            {
                color = ImVec4(0.75f, 0.75f, 0.0f, 1.0f);
            }

            if (mMsgHistory[i].find("ERROR") != std::string::npos)
            {
                color = ImVec4(1.0f, 0.0f, 0.0f, 1.0f);
            }

            const char* msg = mMsgHistory[i].c_str();
            int len = strlen(msg);
            
            ImGui::PushTextWrapPos(ImGui::GetWindowWidth());
            ImGui::TextColored(color, msg);
            ImGui::PopTextWrapPos();
        }

        if (ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
            ImGui::SetScrollHereY(1.0f);
            
        ImGui::EndChild();
        ImGui::Separator();
        ImGui::BeginChild("input", ImVec2(0, 20), false, ImGuiWindowFlags_NoScrollbar);
        mIsFocused = ImGui::IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows);
        if (ImGui::InputText("command", mBuffer, LUA_CON_BUFFER_SIZE, ImGuiInputTextFlags_EnterReturnsTrue 
                            | ImGuiInputTextFlags_CallbackHistory, Console::MyCallback, (void*)this))
        {
            mCommandHistory.push_back(mBuffer);
            memset(mBuffer, 0, LUA_CON_BUFFER_SIZE);
            mbNewCommand = true;

            // Doesn't keep the focus on the input text field
            // Might be another way to do it now
            ImGui::SetKeyboardFocusHere(-1);
            //mAlpha = ImGui::IsWindowFocused() ? 0.75f : 0.1f;
        }

        ImGui::EndChild();

        //mAlpha = mIsFocused ? 0.75f : 0.5f;

        return mIsOpen;
    }

    const std::vector<std::string>* Console::GetCommandHistory() const
    {
        return &mCommandHistory;    
    }

    std::string Console::GetLastCommand()
    {
        return mCommandHistory.back();
    }
    
    bool Console::GetNewCommand(std::string& command)
    {
        if (mbNewCommand)
        {
            command = mCommandHistory.back();
            mbNewCommand = false;
            return true;
        }

        return false;
    }
    

    int Console::MyCallback(ImGuiInputTextCallbackData* data)
    {
        if (data->EventFlag == ImGuiInputTextFlags_CallbackHistory)
        {
            bool changeCommand = false;
            Console* pConsole = (Console*)data->UserData;
            if (data->EventKey == ImGuiKey_UpArrow)
            {
                pConsole->mRecalledCommand--;
                if (pConsole->mRecalledCommand <= -1)
                {
                    pConsole->mRecalledCommand = pConsole->mCommandHistory.size() - 1;
                }
                changeCommand = true;
            }
            else if (data->EventKey == ImGuiKey_DownArrow)
            {
                pConsole->mRecalledCommand++;
                if (pConsole->mRecalledCommand >= pConsole->mCommandHistory.size())
                {
                    pConsole->mRecalledCommand = 0;
                }
                changeCommand = true;
            }

            if (changeCommand)
            {
                memset(pConsole->mBuffer, 0, LUA_CON_BUFFER_SIZE);
                strcpy(pConsole->mBuffer, pConsole->mCommandHistory[pConsole->mRecalledCommand].c_str());
                data->DeleteChars(0, data->BufTextLen);
                data->InsertChars(0, pConsole->mBuffer);
                data->SelectAll();
            }
        }
        return 0;
    }
    
}}