#ifndef utils_h__
#define utils_h__
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <stdarg.h>
#include <iconv.h>
#include <stdio.h>
#include <random>

#define BUFFCOUNT (3196)
#define SET_TEXTW(X) L#X
#define SET_TEXTA(X) #X

namespace Utils
{
	static int Rand(int v_min, int v_max)
	{
		int rNum = 0;
		srand((unsigned int)time(0));
		for (int i = 0; i < 31; i++)
			rNum |= (rand() & 1) << i;
		return v_min + rNum % (v_max - v_min + 1);
	}

	static void *alloc(size_t len)
	{
		int fd = open("/dev/zero", O_RDONLY);
		void *code_addr = mmap(NULL, len, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, fd, 0);
		close(fd);
		return code_addr;
	}

	class NLock
	{
	public:
		typedef pthread_mutex_t OSLockType;

		NLock()
		{
			pthread_mutex_init(&os_lock_, NULL);
		}

		~NLock()
		{
			pthread_mutex_destroy(&os_lock_);
		}

		// If the lock is not held, take it and return true.  If the lock is already
		// held by something else, immediately return false.
		bool Try()
		{
			int rv = pthread_mutex_trylock(&os_lock_);
			return rv == 0;
		}

		// Take the lock, blocking until it is available if necessary.
		void Lock()
		{
			pthread_mutex_lock(&os_lock_);
		}

		// Release the lock.  This must only be called by the lock's holder: after
		// a successful call to Try, or a call to Lock.
		void Unlock()
		{
			pthread_mutex_unlock(&os_lock_);
		}

		// Return the native underlying lock.  Not supported for Windows builds.
		OSLockType *os_lock() { return &os_lock_; }

	private:
		OSLockType os_lock_;
	};

	class NAutoLock
	{
	public:
		NAutoLock(NLock *lock)
		{
			lock_ = lock;
			lock_->Lock();
		}

		~NAutoLock()
		{
			if (lock_)
				lock_->Unlock();
		}

	private:
		NLock *lock_;
	};

	class NAutoUnlock
	{
	public:
		NAutoUnlock(NLock *lock)
		{
			lock_ = lock;
			lock_->Unlock();
		}

		~NAutoUnlock()
		{
			if (lock_)
				lock_->Lock();
		}

	private:
		NLock *lock_;
	};

	template <class V1, class V2, class V3 = std::less<V1>>
	class TMap
	{
	public:
		/**
		 * @brief 保存
		 * @param key
		 * @param data
		 * @return
		 */
		bool Push(V1 key, V2 data)
		{
			NAutoLock auto_lock(&Lock);
			auto itrM = Map.find(key);
			if (itrM != Map.end())
			{
				return false;
			}
			Map.insert(std::make_pair(key, data));
			return true;
		}

		/**
		 * @brief 删除
		 * @param key
		 * @return
		 */
		bool Erase(V1 key)
		{
			NAutoLock auto_lock(&Lock);
			auto itrM = Map.find(key);
			if (itrM != Map.end())
			{
				Map.erase(key);
				return true;
			}
			return false;
		}

		/**
		 * @brief 清空
		 */
		void Clear()
		{
			NAutoLock auto_lock(&Lock);
			Map.clear();
		}

		/**
		 * @brief 大小
		 * @return
		 */
		size_t Size()
		{
			return Map.size();
		}

		/**
		 * @brief 迭代器头
		 * @return
		 */
		typename std::map<V1, V2>::iterator Begin()
		{
			return Map.begin();
		}

		/**
		 * @brief 迭代器尾
		 * @return
		 */
		typename std::map<V1, V2>::iterator End()
		{
			return Map.end();
		}

		/**
		 * @brief 查找数据
		 * @param key
		 * @param data
		 * @return
		 */
		bool Find(V1 key, V2 *data = NULL)
		{
			NAutoLock auto_lock(&Lock);
			auto itr = Map.find(key);
			if (itr != Map.end())
			{
				if (data)
				{
					*data = itr->second;
				}
				return true;
			}
			return false;
		}

		/**
		 * @brief 更改数据
		 * @param key
		 * @param data
		 * @return
		 */
		bool Change(V1 key, V2 data)
		{
			NAutoLock auto_lock(&Lock);
			auto itr = Map.find(key);
			if (itr != Map.end())
			{
				itr->second = data;
				return true;
			}
			return false;
		}

		V2 at(const V1 &__k)
		{
			return Map.at(__k);
		}

		std::map<V1, V2, V3> Map;
		NLock Lock;
	};
	/**
	 * @brief 到16进制Hex文本
	 * @param buf
	 * @param len
	 * @param tok
	 * @return
	 */
	static std::string ToHexString(const unsigned char *buf, int len, std::string tok = " ")
	{
		std::string output;
		char temp[8];
		for (int i = 0; i < len; ++i)
		{
			memset(temp, 0, sizeof(temp));
			snprintf(temp, sizeof(temp), "%.2X", buf[i]);
			output.append(temp, 2);
			output.append(tok);
		}

		return output;
	}

	static int ByteLittleToInt(unsigned char *Count)
	{
		int int1 = Count[0] & 0xff;
		int int2 = (Count[1] & 0xff) << 8;
		int int3 = (Count[2] & 0xff) << 16;
		int int4 = (Count[3] & 0xff) << 24;

		return int1 | int2 | int3 | int4;
	}

	static std::string utf8_to_gbk(const char *utf8String, int length)
	{
		// Open a conversion descriptor
		iconv_t cd = iconv_open("GBK", "UTF-8");
		if (cd == (iconv_t)(-1))
		{
			std::cerr << "Failed to open iconv" << std::endl;
			return std::string(); // Return empty string on failure
		}

		// Prepare buffers
		size_t inbytesleft = length;
		size_t outbytesleft = length * 2; // Assuming worst case for expansion
		char outbuf[outbytesleft + 1];	  // +1 for null termination
		char *inbuf = const_cast<char *>(utf8String);
		char *outptr = outbuf;

		// Perform the conversion
		size_t result = iconv(cd, &inbuf, &inbytesleft, &outptr, &outbytesleft);
		if (result == (size_t)(-1))
		{
			std::cerr << "Conversion failed" << std::endl;
			iconv_close(cd);
			return std::string(); // Return empty string on failure
		}

		// Null-terminate the output buffer
		*outptr = '\0';

		// Close the conversion descriptor
		iconv_close(cd);

		// Return the converted string
		return std::string(outbuf);
	}

	static std::string PackToHexString(const unsigned char *buf, int Offset)
	{
		int Len = ByteLittleToInt((unsigned char *)((int)buf + Offset));
		// char *Buffer = new char[Len + 1];
		// memcpy(Buffer, buf + 17, Len);
		// utf8_to_gbk(Buffer, Len);
		// Buffer[Len] = '\0';
		// std::cout << Buffer << std::endl;
		std::string str((char *)(buf + Offset + 4), Len);
		// std::cout << str << std::endl;
		// delete[] Buffer;
		return str;
	}

	static void _Log(const char *formatstring, ...)
	{
		int nSize = 0;
		char buff[BUFFCOUNT];
		memset(buff, 0, sizeof(buff));
		va_list args;
		va_start(args, formatstring);
		nSize = vsnprintf(buff, sizeof(buff), formatstring, args);
		va_end(args);
		char szPrINT32[BUFFCOUNT + 50] = {0};
		sprintf(szPrINT32, "[DPS_PLUGIN] %s \n", buff); // wsprintfA
		printf(szPrINT32);
	}

}

#define YLOG(format, ...) Utils::_Log(format, ##__VA_ARGS__)

#endif // utils_h__