#include "ComKit.h"
#include "imgui_helper.h"
#include "imgui_stdlib.h"
#include "spdlog/sinks/basic_file_sink.h"
#include "spdlog/sinks/ostream_sink.h"
#include "spdlog/sinks/stdout_color_sinks.h"
#include "spdlog/spdlog.h"
#include <Windows.h>
#include <array>
#include <filesystem>
#include <fstream>
#include <sstream>
#include <toml.h>
namespace filesystem = std::filesystem;

static std::string GetTimeNow() {
    auto now = std::chrono::system_clock::now();
    auto now_c = std::chrono::system_clock::to_time_t(now);
    std::tm now_tm;
    localtime_s(&now_tm, &now_c);

    std::ostringstream oss;
    oss << std::put_time(&now_tm, "%Y-%m-%d");
    return oss.str();
}

constexpr int CLIENT_WIDTH = 500;
constexpr int CLIENT_HEIGHT = 550;
#ifdef _WIN32
int WINAPI WinMain(HINSTANCE hINstance, HINSTANCE preInstance, LPSTR lpCmdLine,
                   int nShowCmd) {
#elif __linux__
int main(int argc, char **) {
#endif
    auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
    console_sink->set_level(spdlog::level::info);
    console_sink->set_pattern("[%T] [%^%l%$] %v");

    auto string_sink =
        std::make_shared<spdlog::sinks::ostream_sink_mt>(ComKit::oss);
    string_sink->set_level(spdlog::level::debug);
    string_sink->set_pattern("[%T] [%^%l%$] %v");

    auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(
        std::format("./log/{}.txt", GetTimeNow()), false);
    file_sink->set_level(spdlog::level::debug);
    file_sink->set_pattern("[%T] [%l] %v");

    std::vector<spdlog::sink_ptr> sinks{console_sink, string_sink, file_sink};
    auto logger = std::make_shared<spdlog::logger>("multi_sink", sinks.begin(),
                                                   sinks.end());
    spdlog::set_default_logger(logger);
    spdlog::set_level(spdlog::level::debug);
    spdlog::flush_on(spdlog::level::info);
    spdlog::flush_every(std::chrono::milliseconds(200));

    const auto comPortNames = ComKit::GetAllComPortNames();
    const int columns = 2;
    bool dontPop = false;
    ImGuiHelper helper{CLIENT_WIDTH, CLIENT_HEIGHT};
    bool isRunning = true;
    std::string filterComName;
    std::string inputCommands;
    std::stringstream oss;
    if (filesystem::exists("./config.toml")) {
        const auto config = toml::parse("./config.toml");
        filterComName = config.at("ComPorts").as_string();
        inputCommands = config.at("Commands").as_string();
    }
    while (isRunning)
        helper.Render(
            [&]() {
                ImGui::Begin("ComKit", &isRunning,
                             ImGuiWindowFlags_NoResize |
                                 ImGuiWindowFlags_NoSavedSettings);

                if (ImGui::BeginTable("StartTable", columns,
                                      ImGuiTableFlags_ScrollY |
                                          ImGuiTableFlags_Resizable |
                                          ImGuiTableFlags_Borders |
                                          ImGuiTableFlags_NoHostExtendX,
                                      ImVec2(CLIENT_WIDTH - 10, 100))) {
                    ImGui::TableSetupColumn("LOCATION_PATHS",
                                            ImGuiTableColumnFlags_WidthFixed);
                    ImGui::TableSetupColumn("COM_PORT_NAME",
                                            ImGuiTableColumnFlags_WidthStretch);
                    ImGui::TableHeadersRow();
                    for (int row = 0; row < comPortNames->size(); row++) {
                        ImGui::TableNextRow();
                        for (int column = 0; column < columns; column++) {
                            ImGui::TableSetColumnIndex(column);
                            if (column == 0) {
                                ImGui::Text("%s",
                                            comPortNames->at(row)
                                                .comPortInstancePath.c_str());
                            } else if (column == 1) {
                                ImGui::Text(
                                    "%s",
                                    comPortNames->at(row).comPortName.c_str());
                            }
                        }
                    }
                    ImGui::EndTable();
                }
                ImGui::Text("Filter Com:");
                ImGui::InputTextMultiline(
                    "comNameFilter", &filterComName,
                    ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 3));
                ImGui::Text("Commands:");
                ImGui::InputTextMultiline(
                    "inputCommands", &inputCommands,
                    ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 5),
                    ImGuiInputTextFlags_AllowTabInput);
                ImGui::Text("Log:");
                ImGui::InputTextMultiline(
                    "logContent", &ComKit::logContent,
                    ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16),
                    ImGuiInputTextFlags_AllowTabInput |
                        ImGuiInputTextFlags_ReadOnly);

                float window_width = ImGui::GetWindowSize().x;
                float start_button_width =
                    ImGui::CalcTextSize("Start").x +
                    ImGui::GetStyle().FramePadding.x * 2.0f;
                float button_start = (window_width - start_button_width) / 2.0f;
                ImGui::SetCursorPosX(button_start);
                if (ImGui::Button("Start")) {
                    ComKit::Start(filterComName, inputCommands);
                }
                ImGui::SameLine();
                auto end_button_width = ImGui::CalcTextSize("End").x +
                                        ImGui::GetStyle().FramePadding.x * 2.0f;
                button_start = (window_width - end_button_width) / 2.0f +
                               start_button_width;
                ImGui::SetCursorPosX(button_start);
                if (ImGui::Button("End")) {
                    ComKit::End();
                }

                if (ComKit::isWorking) {
                    ImGui::SameLine();
                    ImGui::Text("Working");
                }

                ImGui::End();
            },
            isRunning);
    const toml::value v(
        toml::table{{"ComPorts", filterComName}, {"Commands", inputCommands}});
    const auto content = toml::format(v);
    auto file = std::ofstream("./config.toml", std::ios::out | std::ios::trunc);
    file << content;
    file.close();
    return 0;
}
