#include "BaseVisualizer.hpp"

void BaseVisualizer::ClearTerminal() {
    //std::cout << "\033[2J";
    system("cls");
}

std::vector<std::vector<std::string>>* BaseVisualizer::GetDisplayVector() {
    return &display_vector;
}

size_t BaseVisualizer::CountVisibleCharacters(const std::string& str) {
    size_t count = 0;
    size_t i = 0;

    while (i < str.size()) {
        if (str[i] == '\x1B' && i + 1 < str.size() && str[i + 1] == '[') {
            // ANSI-Escape-Sequenz erkennen und überspringen
            i += 2; // Überspringe '\x1B['
            while (i < str.size() && !std::isalpha(str[i])) {
                ++i; // Fortsetzung der Sequenz überspringen
            }
            if (i < str.size() && std::isalpha(str[i])) {
                ++i; // Buchstaben am Ende der Sequenz überspringen
            }
        } else {
            // UTF-8 Startbytes zählen (kein Fortsetzungsbyte)
            if ((str[i] & 0b11000000) != 0b10000000) {
                ++count;
            }
            ++i;
        }
    }

    return count;
}

size_t BaseVisualizer::GetSumAllCharsFromVector(const std::vector<std::string>& vec) {
    size_t sum = 0;
    for (const std::string& str : vec) {
        sum += CountVisibleCharacters(str);
    }
    return sum;
}

void BaseVisualizer::GenerateEmptyLine(const int lengthOfMenu, const bool single) {
    std::string result = "";
    for (int i = 0; i < lengthOfMenu; ++i) {
        if (i == 0) {
            result += ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE);
        } else if (i == lengthOfMenu-1) {
            result += ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE);
        } else {
            result += " ";
        }
    }
    display_vector.push_back({result});
}

// ToDo: Auf Max länge bringen
void BaseVisualizer::GenerateBoxMenuLine(const size_t length, const std::string& str, const bool single, const size_t padding) {
    std::string result = ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE) + std::string(padding, ' ') + str;
    while (CountVisibleCharacters(result) < length-1) {
        result += " ";
    }
    display_vector.push_back({result.append(((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE))});
}

void BaseVisualizer::GenerateCenteredString(const size_t widthOfMenu, const std::string& str, const bool single) {
    std::string result = (single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE;

    float newLength = widthOfMenu - CountVisibleCharacters(str) - 2;

    int firstHalfLength = std::floor(newLength / 2);
    int secondHalfLength = std::ceil(newLength / 2);

    for (int i = 0; i < firstHalfLength; ++i) {
        result += " ";
    }

    result += str;

    for (int i = 0; i < secondHalfLength; ++i) {
        result += " ";
    }

    display_vector.push_back({result+ ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE)});
}

void BaseVisualizer::DisplayElement() {
  int temp;
    for (const auto& row : display_vector) {
        for (const auto& cell : row) {
            std::cout << cell;
        }
        std::cout << std::endl;
    }
    std::cout << "\x1B[u";
    //std::cout << "Select option" << std::endl;
    std::cin >> temp;
}

size_t BaseVisualizer::CalculateMaxMenuWidth(const size_t longestStringLength, const size_t padding) {
  return longestStringLength + 2*padding + 2;
}

void BaseVisualizer::GenerateTopBottomBorder(const size_t totalLength, const bool top, const bool single) {
    std::string result = (top) ? ((single) ? BaseVisualizer::TOP_LEFT_CORNER_SINGLE : BaseVisualizer::TOP_LEFT_CORNER) : ((single) ? BaseVisualizer::BOTTOM_LEFT_CORNER_SINGLE : BaseVisualizer::BOTTOM_LEFT_CORNER);
    for (size_t i = 0; i < totalLength-2; ++i) {
        result += (single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE;
    }
    display_vector.push_back({result + ((top) ? ((single) ? BaseVisualizer::TOP_RIGHT_CORNER_SINGLE : BaseVisualizer::TOP_RIGHT_CORNER) : ((single) ? BaseVisualizer::BOTTOM_RIGHT_CORNER_SINGLE : BaseVisualizer::BOTTOM_RIGHT_CORNER))});
}

void BaseVisualizer::AddEmptyLines(const size_t lines, const size_t length, const bool sinlge) {
  for (size_t i = 0; i < lines; ++i) {
    BaseVisualizer::GenerateEmptyLine(length, sinlge);
  }
}

void BaseVisualizer::GenerateTableTopBottom(const size_t totalLength, const bool top, const bool single) {
    int firstHalfLength = std::floor(totalLength / 2);

    std::string result = (top) ? ((single) ? BaseVisualizer::TOP_LEFT_CORNER_SINGLE : BaseVisualizer::TOP_LEFT_CORNER) : ((single) ? BaseVisualizer::BOTTOM_LEFT_CORNER_SINGLE : BaseVisualizer::BOTTOM_LEFT_CORNER);

    for (size_t i = 0; i < firstHalfLength-1; ++i) {
        result += (single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE;
    }

    result += (top) ? ((single) ? BaseVisualizer::TOP_CROSS_SINGLE : BaseVisualizer::TOP_CROSS) : ((single) ? BaseVisualizer::BOTTOM_CROSS_SINGLE : BaseVisualizer::BOTTOM_CROSS);

    for (size_t i = 0; i < firstHalfLength-1; ++i) {
        result += (single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE;
    }

    display_vector.push_back({result + ((top) ? ((single) ? BaseVisualizer::TOP_RIGHT_CORNER_SINGLE : BaseVisualizer::TOP_RIGHT_CORNER) : ((single) ? BaseVisualizer::BOTTOM_RIGHT_CORNER_SINGLE : BaseVisualizer::BOTTOM_RIGHT_CORNER))});
}

void BaseVisualizer::GenerateTableLine(const float length, const std::vector<std::string>& str, const bool single) {
    int firstHalfLength = std::floor(length / 2);
    std::string result = ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE);
    std::string temp;

    for (size_t i = 0; i < 2; ++i) {
         temp += "  " + str[i];

        while (CountVisibleCharacters(temp) < firstHalfLength-1) {
            temp += " ";
        }
        temp += ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE);
        result += temp;
        temp = "";
    }
    display_vector.push_back({result});
}

void BaseVisualizer::GenerateTableSeperator(const float length, const bool single) {
    int firstHalfLength = std::floor(length / 2);
    std::string result = ((single) ? BaseVisualizer::RIGHT_CROSS_SINGLE : BaseVisualizer::RIGHT_CROSS);
    std::string temp;

    for (size_t i = 0; i < 2; ++i) {
        while (CountVisibleCharacters(temp) < firstHalfLength-1) {
            temp += ((single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE);
        }
        temp += (i != 1) ? ((single) ? BaseVisualizer::CROSS_SINGLE : BaseVisualizer::CROSS) : "";
        result += temp;
        temp = "";
    }
    result += ((single) ? BaseVisualizer::LEFT_CROSS_SINGLE : BaseVisualizer::LEFT_CROSS);

    display_vector.push_back({result});
}

void BaseVisualizer::GenerateBoxSeperator(const float length, const bool single) {
    std::string result = ((single) ? BaseVisualizer::RIGHT_CROSS_SINGLE : BaseVisualizer::RIGHT_CROSS);

    while (CountVisibleCharacters(result) < length-1) {
        result += ((single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE);
    }

    result += ((single) ? BaseVisualizer::LEFT_CROSS_SINGLE : BaseVisualizer::LEFT_CROSS);

    display_vector.push_back({result});
}

void BaseVisualizer::SetConsoleColor(Colors foreground, Colors background) {
  const std::string SEQ_FOREGROUND = "\x1b[3";
  const std::string SEQ_FOREGROUND_LIGHT = "\x1b[9";
  const std::string SEQ_BACKGROUND = "\x1b[4";
  const std::string SEQ_BACKGROUND_LIGHT = "\x1b[10";

  // set foreground color
  switch (foreground) {
    case BLACK:
    case RED:
    case GREEN:
    case YELLOW:
    case BLUE:
    case MAGENTA:
    case CYAN:
    case WHITE:
      std::cout << SEQ_FOREGROUND << foreground << "m";
      break;
    case LIGHT_BLACK:
    case LIGHT_RED:
    case LIGHT_GREEN:
    case LIGHT_YELLOW:
    case LIGHT_BLUE:
    case LIGHT_MAGENTA:
    case LIGHT_CYAN:
    case LIGHT_WHITE:
      std::cout << SEQ_FOREGROUND_LIGHT << foreground << "m";
      break;
    case DEFAULT:
    default:
      std::cout << SEQ_FOREGROUND << foreground << "m";
      break;
  }

  // set background color
  switch (background) {
    case BLACK:
    case RED:
    case GREEN:
    case YELLOW:
    case BLUE:
    case MAGENTA:
    case CYAN:
    case WHITE:
      std::cout << SEQ_BACKGROUND << background << "m";
      break;
    case LIGHT_BLACK:
    case LIGHT_RED:
    case LIGHT_GREEN:
    case LIGHT_YELLOW:
    case LIGHT_BLUE:
    case LIGHT_MAGENTA:
    case LIGHT_CYAN:
    case LIGHT_WHITE:
      std::cout << SEQ_BACKGROUND_LIGHT << background << "m";
      break;
    case DEFAULT:
    default:
      std::cout << SEQ_BACKGROUND << background << "m";
      break;
  }
}

size_t BaseVisualizer::FindMaxLength(const std::vector<std::string> vec) {
    size_t max = 0;
    size_t currentLength = 0;
    for (const std::string& str : vec) {
        currentLength = CountVisibleCharacters(str);
        (currentLength > max) ? max = CountVisibleCharacters(str) : max;
    }
    return max;
}