#include "utils.h"

HSV RGB565toHSV(uint16_t color) {
  uint8_t r = ((color >> 11) & 0x1F) * 8;  // Convert 5-bit to 8-bit
  uint8_t g = ((color >> 5) & 0x3F) * 4;   // Convert 6-bit to 8-bit
  uint8_t b = (color & 0x1F) * 8;          // Convert 5-bit to 8-bit

  float rf = r / 255.0, gf = g / 255.0, bf = b / 255.0;
  float maxVal = max(rf, max(gf, bf));
  float minVal = min(rf, min(gf, bf));
  float delta = maxVal - minVal;

  HSV hsv;
  hsv.v = maxVal;

  if (delta < 0.0001) {
    hsv.h = 0;
    hsv.s = 0;
  } else {
    hsv.s = delta / maxVal;

    if (maxVal == rf) hsv.h = fmod(((gf - bf) / delta), 6.0);
    else if (maxVal == gf) hsv.h = ((bf - rf) / delta) + 2.0;
    else hsv.h = ((rf - gf) / delta) + 4.0;

    hsv.h *= 60.0;
    if (hsv.h < 0) hsv.h += 360.0;
  }
  return hsv;
}

uint16_t HSVtoRGB565(float h, float s, float v) {
  float c = v * s;
  float x = c * (1 - fabs(fmod(h / 60.0, 2) - 1));
  float m = v - c;

  float rf, gf, bf;
  if (h < 60) rf = c, gf = x, bf = 0;
  else if (h < 120) rf = x, gf = c, bf = 0;
  else if (h < 180) rf = 0, gf = c, bf = x;
  else if (h < 240) rf = 0, gf = x, bf = c;
  else if (h < 300) rf = x, gf = 0, bf = c;
  else rf = c, gf = 0, bf = x;

  uint8_t r = (rf + m) * 255;
  uint8_t g = (gf + m) * 255;
  uint8_t b = (bf + m) * 255;

  return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}

String convertToUTF8(const wchar_t* input) {
  String output;
  while (*input) {
    uint32_t unicode = *input;
    if (unicode < 0x80) output += (char)unicode;
    else if (unicode < 0x800) {
      output += (char)(0xC0 | (unicode >> 6));
      output += (char)(0x80 | (unicode & 0x3F));
    } else if (unicode < 0x10000) {
      output += (char)(0xE0 | (unicode >> 12));
      output += (char)(0x80 | ((unicode >> 6) & 0x3F));
      output += (char)(0x80 | (unicode & 0x3F));
    } else {
      output += (char)(0xF0 | (unicode >> 18));
      output += (char)(0x80 | ((unicode >> 12) & 0x3F));
      output += (char)(0x80 | ((unicode >> 6) & 0x3F));
      output += (char)(0x80 | (unicode & 0x3F));
    }
    input++;
  }
  return output;
}

String trimTrailingSpaces(String str) {
  int end = str.length() - 1;
  while (end >= 0 && isspace(str[end])) end--;
  return str.substring(0, end + 1);
}

String ucs2ToUtf8(const char* ucs2Input) {
  String utf8Output;

  size_t length = 0;
  while (ucs2Input[length] != '\0' || ucs2Input[length + 1] != '\0') length += 2;

  for (size_t i = 0; i < length; i += 2) {
    uint16_t ucs2Char = ((uint8_t)ucs2Input[i] << 8) | (uint8_t)ucs2Input[i + 1];

    if (ucs2Char <= 0x7F) utf8Output += (char)ucs2Char;
    else if (ucs2Char <= 0x7FF) {
      utf8Output += (char)(0xC0 | (ucs2Char >> 6));
      utf8Output += (char)(0x80 | (ucs2Char & 0x3F));
    } else {
      utf8Output += (char)(0xE0 | (ucs2Char >> 12));
      utf8Output += (char)(0x80 | ((ucs2Char >> 6) & 0x3F));
      utf8Output += (char)(0x80 | (ucs2Char & 0x3F));
    }
  }
  return utf8Output;
}

String extractUTF8Substring(const String & utf8String, size_t start, size_t length, bool underscore) {
  String substring;
  size_t utf8Length = utf8String.length();
  size_t utf8Index = 0;
  size_t charIndex = 0;

  while (utf8Index < utf8Length && charIndex < start + length) {
    uint8_t currentByte = utf8String.charAt(utf8Index);
    uint8_t numBytes = 0;

    if (currentByte < 0x80) numBytes = 1;
    else if ((currentByte >> 5) == 0x6) numBytes = 2;
    else if ((currentByte >> 4) == 0xE) numBytes = 3;
    else if ((currentByte >> 3) == 0x1E) numBytes = 4;

    if (charIndex >= start) substring += utf8String.substring(utf8Index, utf8Index + numBytes);

    utf8Index += numBytes;
    charIndex++;
  }

  if (underscore) {
    while (substring.length() < length) substring += '_';
  }

  return substring;
}

String removeNewline(String inputString) {
  String outputString = "";
  for (int i = 0; i < inputString.length(); i++) {
    if (inputString[i] == '\n') outputString += ' ';
    else outputString += inputString[i];
  }
  return outputString;
}