#include <iostream>
#include <print>
#include <vector>

#include "include/cache.hpp"
#include "include/paging.hpp"
#include "include/password.hpp"

#include <openssl/sha.h>

int main() {
  std::vector<int> pages = {7, 0, 1, 2, 0, 3, 0, 4, 2, 3, 0, 3};
  int frames = 3;

  paging::optimal_replacer opt(frames);
  paging::clock_replacer clk(frames);
  paging::lru_replacer lru(frames);

  std::println("Optimal faults: {}", opt.run(pages));
  std::println("Clock   faults: {}", clk.run(pages));
  std::println("LRU     faults: {}", lru.run(pages));

  std::println("\nCache LRU Simulation:");
  cache::lru cache(128, 4);
  std::vector<uint64_t> addresses = {
      0, 1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192,
  };
  int32_t hits = 0, misses = 0;
  for (auto addr : addresses) {
    if (cache.access(addr)) {
      ++hits;
      std::println("Address 0x{:x}:\t HIT", addr);
    } else {
      ++misses;
      std::println("Address 0x{:x}:\t MISS", addr);
    }
  }
  std::println("Hits: {}, Misses: {}\n", hits, misses);

  auto pwd = sec::password::from_console();
  auto strength = sec::manager::evaluate_strength(pwd);
  auto crack_time = sec::manager::time_to_crack(pwd);
  auto crack_str = sec::manager::format_duration(crack_time);

  std::print("Password strength: ");
  switch (strength) {
  case sec::strength_t::very_weak:
    std::print("Very Weak");
    break;
  case sec::strength_t::weak:
    std::print("Weak");
    break;
  case sec::strength_t::moderate:
    std::print("Moderate");
    break;
  case sec::strength_t::strong:
    std::print("Strong");
    break;
  case sec::strength_t::very_strong:
    std::print("Very Strong");
    break;
  }
  std::print("\nEstimated time to crack: {} secs\n({})\n", crack_time,
             crack_str);

  std::string input;
  std::print("\nEnter password to verify: ");
  std::getline(std::cin, input);
  auto input_pwd = sec::password::from_string(input);
  if (pwd.to_hash().verify(input_pwd)) {
    std::print("Password verified successfully.\n");
  }
}
