#include "WebUserLoginDialog.hpp"

#include <string.h>
#include "I18N.hpp"
#include "libslic3r/AppConfig.hpp"
#include "slic3r/GUI/wxExtensions.hpp"
#include "slic3r/GUI/GUI_App.hpp"
#include "libslic3r_version.h"

#include <wx/sizer.h>
#include <wx/toolbar.h>
#include <wx/textdlg.h>

#include <wx/wx.h>
#include <wx/fileconf.h>
#include <wx/file.h>
#include <wx/wfstream.h>

#include <boost/cast.hpp>
#include <boost/lexical_cast.hpp>

#include "MainFrame.hpp"
#include <boost/dll.hpp>

#include <sstream>
#include <slic3r/GUI/Widgets/WebView.hpp>
#include "../QIDI/QIDINetwork.hpp"
#include <nlohmann/json.hpp>


using namespace std;
using namespace nlohmann;


namespace Slic3r {
    namespace GUI {

#define NETWORK_OFFLINE_TIMER_ID 10001

        BEGIN_EVENT_TABLE(ZUserLogin, wxDialog)
            EVT_TIMER(NETWORK_OFFLINE_TIMER_ID, ZUserLogin::OnTimer)
            END_EVENT_TABLE()

            int ZUserLogin::web_sequence_id = 20000;

        ZUserLogin::ZUserLogin() : wxDialog((wxWindow*)(wxGetApp().mainframe), wxID_ANY, "QIDIStudio")
        {
            SetBackgroundColour(*wxWHITE);
            TargetUrl = "";

#if QDT_RELEASE_TO_PUBLIC
            wxString    msg;
            QIDINetwork m_qidinetwork;
            TargetUrl = m_qidinetwork.get_qidi_host();
#endif


            BOOST_LOG_TRIVIAL(error) << "login url = " << TargetUrl.ToStdString();


            m_qdt_user_agent = wxString::Format("QDT-Slicer/v%s", SLIC3R_VERSION);

            // set the frame icon

            // Create the webview
            m_browser = WebView::CreateWebView(this, TargetUrl);
            if (m_browser == nullptr) {
                wxLogError("Could not init m_browser");
                return;
            }
            m_browser->Hide();
            m_browser->SetSize(0, 0);

            Bind(wxEVT_WEBVIEW_NAVIGATING, &ZUserLogin::OnNavigationRequest, this, m_browser->GetId());
            Bind(wxEVT_WEBVIEW_NAVIGATED, &ZUserLogin::OnNavigationComplete, this, m_browser->GetId());
            Bind(wxEVT_WEBVIEW_LOADED, &ZUserLogin::OnDocumentLoaded, this, m_browser->GetId());
            Bind(wxEVT_WEBVIEW_ERROR, &ZUserLogin::OnError, this, m_browser->GetId());
            Bind(wxEVT_WEBVIEW_NEWWINDOW, &ZUserLogin::OnNewWindow, this, m_browser->GetId());
            Bind(wxEVT_WEBVIEW_TITLE_CHANGED, &ZUserLogin::OnTitleChanged, this, m_browser->GetId());
            Bind(wxEVT_WEBVIEW_FULLSCREEN_CHANGED, &ZUserLogin::OnFullScreenChanged, this, m_browser->GetId());
            Bind(wxEVT_WEBVIEW_SCRIPT_MESSAGE_RECEIVED, &ZUserLogin::OnScriptMessage, this, m_browser->GetId());

            // UI
            SetTitle(_L("Login"));
            wxSize pSize = FromDIP(wxSize(650, 840));
            SetSize(pSize);

            int     screenheight = wxSystemSettings::GetMetric(wxSYS_SCREEN_Y, NULL);
            int     screenwidth = wxSystemSettings::GetMetric(wxSYS_SCREEN_X, NULL);
            int     MaxY = (screenheight - pSize.y) > 0 ? (screenheight - pSize.y) / 2 : 0;
            wxPoint tmpPT((screenwidth - pSize.x) / 2, MaxY);
            Move(tmpPT);
        }

        ZUserLogin::~ZUserLogin()
        {
            if (m_timer != NULL) {
                m_timer->Stop();
                delete m_timer;
                m_timer = NULL;
            }
        }

        void ZUserLogin::OnTimer(wxTimerEvent& event)
        {
            m_timer->Stop();

            if (m_networkOk == false) {
                ShowErrorPage();
            }
        }

        bool ZUserLogin::run()
        {
            m_timer = new wxTimer(this, NETWORK_OFFLINE_TIMER_ID);
            m_timer->Start(8000);

            if (this->ShowModal() == wxID_OK) {
                return true;
            }
            else {
                return false;
            }
        }

        void ZUserLogin::load_url(wxString& url)
        {
            m_browser->LoadURL(url);
            m_browser->SetFocus();
            UpdateState();
        }

        /**
         * Method that retrieves the current state from the web control and updates
         * the GUI the reflect this current state.
         */
        void ZUserLogin::UpdateState()
        {
            // SetTitle(m_browser->GetCurrentTitle());
        }

        void ZUserLogin::OnIdle(wxIdleEvent& WXUNUSED(evt))
        {
            if (m_browser->IsBusy()) {
                wxSetCursor(wxCURSOR_ARROWWAIT);
            }
            else {
                wxSetCursor(wxNullCursor);
            }
        }

        // void ZUserLogin::OnClose(wxCloseEvent& evt)
        //{
        //    this->Hide();
        //}

        /**
         * Callback invoked when there is a request to load a new page (for instance
         * when the user clicks a link)
         */
        void ZUserLogin::OnNavigationRequest(wxWebViewEvent& evt)
        {
            // wxLogMessage("%s", "Navigation request to '" + evt.GetURL() + "'(target='" + evt.GetTarget() + "')");

            UpdateState();
        }

        /**
         * Callback invoked when a navigation request was accepted
         */
        void ZUserLogin::OnNavigationComplete(wxWebViewEvent& evt)
        {
            // wxLogMessage("%s", "Navigation complete; url='" + evt.GetURL() + "'");
            m_browser->Show();
            Layout();
            UpdateState();
        }

        /**
         * Callback invoked when a page is finished loading
         */
        void ZUserLogin::OnDocumentLoaded(wxWebViewEvent& evt)
        {
            // Only notify if the document is the main frame, not a subframe
            wxString      tmpUrl = evt.GetURL();

            UpdateState();
        }

        /**
         * On new window, we veto to stop extra windows appearing
         */
        void ZUserLogin::OnNewWindow(wxWebViewEvent& evt)
        {
            wxString flag = " (other)";

            if (evt.GetNavigationAction() == wxWEBVIEW_NAV_ACTION_USER) {
                flag = " (user)";
            }

            // wxLogMessage("%s", "New window; url='" + evt.GetURL() + "'" + flag);

            // If we handle new window events then just load them in this window as we
            // are a single window browser
            m_browser->LoadURL(evt.GetURL());

            UpdateState();
        }

        void ZUserLogin::OnTitleChanged(wxWebViewEvent& evt)
        {
            // SetTitle(evt.GetString());
            // wxLogMessage("%s", "Title changed; title='" + evt.GetString() + "'");
        }

        void ZUserLogin::OnFullScreenChanged(wxWebViewEvent& evt)
        {
            // wxLogMessage("Full screen changed; status = %d", evt.GetInt());
            ShowFullScreen(evt.GetInt() != 0);
        }

        void ZUserLogin::OnScriptMessage(wxWebViewEvent& evt)
        {
            wxString str_input = evt.GetString();
            BOOST_LOG_TRIVIAL(error) << evt.GetString();
            std::string token;
            try {
                json j = json::parse(into_u8(str_input));
                token = j["data"]["token"];
            }
            catch (std::exception& e) {
                wxMessageBox(e.what(), "parse json failed", wxICON_WARNING);
                Close();
            }
            BOOST_LOG_TRIVIAL(error) << token;
            wxGetApp().app_config->set("user_token", token);
            Close();
            wxGetApp().SetOnlineLogin((token != ""));

            ////wxLogMessage("Script message received; value = %s, handler = %s", evt.GetString(), evt.GetMessageHandler());
        }

        void ZUserLogin::RunScript(const wxString& javascript)
        {
            // Remember the script we run in any case, so the next time the user opens
            // the "Run Script" dialog box, it is shown there for convenient updating.
            m_javascript = javascript;

            if (!m_browser)
                return;

            WebView::RunScript(m_browser, javascript);
        }
#if wxUSE_WEBVIEW_IE
        void ZUserLogin::OnRunScriptObjectWithEmulationLevel(wxCommandEvent& WXUNUSED(evt))
        {
            wxWebViewIE::MSWSetModernEmulationLevel();
            RunScript("function f(){var person = new Object();person.name = 'Foo'; \
    person.lastName = 'Bar';return person;}f();");
            wxWebViewIE::MSWSetModernEmulationLevel(false);
        }

        void ZUserLogin::OnRunScriptDateWithEmulationLevel(wxCommandEvent& WXUNUSED(evt))
        {
            wxWebViewIE::MSWSetModernEmulationLevel();
            RunScript("function f(){var d = new Date('10/08/2017 21:30:40'); \
    var tzoffset = d.getTimezoneOffset() * 60000; return \
    new Date(d.getTime() - tzoffset);}f();");
            wxWebViewIE::MSWSetModernEmulationLevel(false);
        }

        void ZUserLogin::OnRunScriptArrayWithEmulationLevel(wxCommandEvent& WXUNUSED(evt))
        {
            wxWebViewIE::MSWSetModernEmulationLevel();
            RunScript("function f(){ return [\"foo\", \"bar\"]; }f();");
            wxWebViewIE::MSWSetModernEmulationLevel(false);
        }
#endif

        /**
         * Callback invoked when a loading error occurs
         */
        void ZUserLogin::OnError(wxWebViewEvent& evt)
        {
#define WX_ERROR_CASE(type) \
    case type: category = #type; break;

            wxString category;
            switch (evt.GetInt()) {
                WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_CONNECTION);
                WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_CERTIFICATE);
                WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_AUTH);
                WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_SECURITY);
                WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_NOT_FOUND);
                WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_REQUEST);
                WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_USER_CANCELLED);
                WX_ERROR_CASE(wxWEBVIEW_NAV_ERR_OTHER);
            }

            if (evt.GetInt() == wxWEBVIEW_NAV_ERR_CONNECTION) {
                if (m_timer != NULL)
                    m_timer->Stop();

                if (m_networkOk == false)
                    ShowErrorPage();
            }

            // wxLogMessage("%s", "Error; url='" + evt.GetURL() + "', error='" +
            // category + " (" + evt.GetString() + ")'");

            // Show the info bar with an error
            // m_info->ShowMessage(_L("An error occurred loading ") + evt.GetURL() +
            // "\n" + "'" + category + "'", wxICON_ERROR);

            UpdateState();
        }

        void ZUserLogin::OnScriptResponseMessage(wxCommandEvent& WXUNUSED(evt))
        {
            // if (!m_response_js.empty())
            //{
            //    RunScript(m_response_js);
            //}

            // RunScript("This is a message to Web!");
            // RunScript("postMessage(\"AABBCCDD\");");
        }

        bool ZUserLogin::ShowErrorPage()
        {
            wxString ErrortUrl = from_u8((boost::filesystem::path(resources_dir()) / "web\\login\\error.html").make_preferred().string());
            load_url(ErrortUrl);

            return true;
        }

    }
} // namespace Slic3r::GUI
