// Copyright 2025 Oliver Theimer
#pragma once
#include <algorithm>
#include <iostream>
#include <string>
#include <utility>
#include <vector>

#include "../bbdd/include/bbdd_node.hpp"
#include "kitty/cube.hpp"
#include "mockturtle/networks/cover.hpp"
#include <kitty/kitty.hpp>
#include <mockturtle/mockturtle.hpp>

class Util {
 public:
  /**
   * @brief converts cover node to boolean function information
   *
   * @param cover cover node that stores the cubes
   * @return the represented boolean function of the cubes
   */
  static bbdd_op_t
  cube_to_bbdd_op(std::pair<std::vector<kitty::cube>, bool> const &cover) {
    bbdd_op_t type = bbdd_none;
    // on-set
    if (cover.second) {
      if (cover.first.size() == 1) {
        if (cover.first[0] == kitty::cube("11")) {
          type = bbdd_and;
        } else if (cover.first[0] == kitty::cube("0")) {
          type = bbdd_inv;
        } else if (cover.first[0] == kitty::cube("00")) {
          type = bbdd_and;
        } else if (cover.first[0] == kitty::cube("01")) {
          type = bbdd_notand;
        } else if (cover.first[0] == kitty::cube("10")) {
          type = bbdd_andnot;
        } else if (cover.first[0] == kitty::cube("1")) {
          type = bbdd_buf;
        } else if (cover.first[0] == kitty::cube("")) {
          type = bbdd_one;
        }
      } else if (cover.first.size() == 2) {
        if (cover.first[0] == kitty::cube("1-") &&
            cover.first[1] == kitty::cube("-1")) {
          type = bbdd_or;
        } else if (cover.first[0] == kitty::cube("10") &&
                   cover.first[1] == kitty::cube("01")) {
          type = bbdd_xor;
        } else if (cover.first[0] == kitty::cube("11") &&
                   cover.first[1] == kitty::cube("00")) {
          type = bbdd_xnor;
        }
      } else if (cover.first.size() == 3) {
        if (cover.first[0] == kitty::cube("10") &&
            cover.first[1] == kitty::cube("01") &&
            cover.first[0] == kitty::cube("11")) {
          type = bbdd_or;
        }
      }
    } else if (!cover.second) {
      // off-set
      if (cover.first.size() == 1) {
        if (cover.first[0] == kitty::cube("")) {
          type = bbdd_zero;
        }
        if (cover.first[0] == kitty::cube("00")) {
          type = bbdd_or;
        } else if (cover.first[0] == kitty::cube("01")) {
          type = bbdd_ornot;
        } else if (cover.first[0] == kitty::cube("10")) {
          type = bbdd_notor;
        } else if (cover.first[0] == kitty::cube("11")) {
          type = bbdd_nor;
        }
      }
    }
    if (type == bbdd_none) {
      kitty::print_cubes(cover.first);
    }
    assert(type != bbdd_none && "[ERROR] cube function not implemented\n");
    return type;
  }

  /**
   * @brief displays progress bar based on given input. Is used to display
   * progress of converting cover graph to optimization data structure
   *
   * @param progress_v needs the format (name, (share, base))
   * @param bar_width total width in caracters for the progress bar
   */
  static void show_progress_bar(
      std::vector<std::pair<std::string, std::pair<int, int>>> progress_v,
      int bar_width) {
    for (std::pair<std::string, std::pair<int, int>> progress : progress_v) {
      std::string name = progress.first;
      int share = progress.second.first;
      int base = progress.second.second;
      int current_width = bar_width / progress_v.size();
      float percent = static_cast<float>(share) / base;
      int pos = percent * current_width;
      std::cout << name << ": [";
      for (int i = 0; i < current_width; i++) {
        if (i < pos)
          std::cout << "=";
        else if (i == pos)
          std::cout << ">";
        else
          std::cout << " ";
      }
      std::cout << "] " << share << "/" << base << " "
                << static_cast<int>(percent * 100) << "% ";
    }
    std::cout << " \r";
    std::cout.flush();
  }
};
