#pragma once
#include <ColorConsole.hpp>
#include <chrono>
#include <cstdint>
#include <filecomplete.h>
#include <fmt/format.h>
#include <functional>
#include <iomanip>
#include <sstream>

#include "of_util.h"

constexpr size_t g_BuffSize = 102400;
const size_t MAX_FRAME_SIZE = 10 * g_BuffSize;
enum FrameType : int16_t {
    TYPE_DEFAULT = 0,
    TYPE_GET_LIST,
    TYPE_DOWN_LIST,
    TYPE_UP_LIST,
    TYPE_CANCEL_LIST,
    TYPE_OPEN_FILE,
    TYPE_OPEN_FAILED,
    TYPE_TRANS_FILE,
    TYPE_TRANS_DONE,
    TYPE_INTERRUPT,
    TYPE_NO_HIT_TASK,
    TYPE_WAITTING,
    TYPE_HEARTS,
    TYPE_OFFLINE,
    TYPE_JUDGE_ACTIVE,
    TYPE_REQUEST_UPDATE_LIST,
    TYPE_REQUEST_DOWN_UPDATE_LIST,
    TYPE_CONFIRM_UPDATE_LIST,
    TYPE_UNCONFIRM_UPDATE_LIST,
    TYPE_DONE_UPDATE_LIST,
    TYPE_BUSY_UPDATE_LIST,
    TYPE_FAILED_UPDATE_LIST,
    TYPE_GET_ID,
    TYPE_FILE_INFO,
    TYPE_GET_DIRFILES,
    TYPE_GET_DIRFILES_DONE,
    TYPE_GET_DIRFILES_FAILED,
};

// 此结构体成员顺序不可变动，涉及到序列化反序列化。
struct CMessageInfo {
    CMessageInfo(const std::string& id);
    CMessageInfo(const CMessageInfo& info);
    CMessageInfo& operator=(const CMessageInfo& info);
    std::string id;
    std::string uuid;
    std::string str;
    std::string data;
};

void serialize(CMessageInfo& msg_info, char** out_buf, int& len);
bool deserialize(char* data, int len, CMessageInfo& msg_info);
std::string u8tolocal(const std::string& str);
std::string localtou8(const std::string& str);
void hash(const char* data, uint8_t k[32]);
void rdm(uint8_t* o, size_t size);
bool encrypt(const uint8_t* k, uint8_t* m, size_t len);
bool decrypt(const uint8_t* k, uint8_t* m, size_t len);

using namespace ofen;
class CFrameBuffer
{
public:
    CFrameBuffer();
    ~CFrameBuffer();

public:
    std::string fid_{};
    std::string tid_{};

public:
    FrameType type_{};
    char* data_{};
    int len_{};
    char mark_{};
};

using ExFun_t = std::function<void(CFrameBuffer* buf)>;
/*
【 transm TCP 数据协议 】
    header 2 char: 0xFF 0xFE
    type   2 char:
    mark   1 char:
    from  32 char:
    to    32 char:
    len    4 char:
    data    xxxxx:
    tail   2 char: 0xFF 0xFF
 */
class CTransProtocal
{
public:
    CTransProtocal();
    ~CTransProtocal();

public:
    static CFrameBuffer* parse(CMutBuffer& buffer);
    static bool pack(CFrameBuffer* buf, char** out_buf, int& len);
    static void display_progress(float percent);
};

inline std::string now_str()
{
    auto now = std::chrono::system_clock::now();
    auto time_t_now = std::chrono::system_clock::to_time_t(now);
    auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;

    std::ostringstream timestamp;
    timestamp << std::put_time(std::localtime(&time_t_now), "[%m-%d %H:%M:%S") << "." << std::setfill('0')
              << std::setw(3) << milliseconds.count() << "] ";

    return timestamp.str();
}

template <typename... Args> void TLOGI(const std::string& format, Args&&... args)
{
    fc_lock_print();
    std::cout << ConsoleColor::Green << fmt::format(now_str() + format, std::forward<Args>(args)...)
              << std::endl;
    fc_unlock_print();
}

template <typename... Args> void TLOGW(const std::string& format, Args&&... args)
{
    fc_lock_print();
    std::cout << ConsoleColor::Yellow << fmt::format(now_str() + format, std::forward<Args>(args)...)
              << std::endl;
    fc_unlock_print();
}

template <typename... Args> void TLOGE(const std::string& format, Args&&... args)
{
    fc_lock_print();
    std::cout << ConsoleColor::Red << fmt::format(now_str() + format, std::forward<Args>(args)...)
              << std::endl;
    fc_unlock_print();
}

template <typename... Args> void TLOGD(const std::string& format, Args&&... args)
{
    fc_lock_print();
    std::cout << ConsoleColor::Cyan << fmt::format(now_str() + format, std::forward<Args>(args)...)
              << std::endl;
    fc_unlock_print();
}