#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>

#include <algorithm>
#include <chrono>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <sstream>
#include <string>
#include <thread>
#include <vector>

namespace {

void send_response(int client, int status, const std::string& status_text,
                   const std::string& body) {
  const std::string response =
      "HTTP/1.1 " + std::to_string(status) + " " + status_text + "\r\n" +
      "Content-Type: text/plain; charset=utf-8\r\n" +
      "Content-Length: " + std::to_string(body.size()) + "\r\n" +
      "Connection: close\r\n\r\n" + body;
  send(client, response.c_str(), response.size(), 0);
}

void create_cpu_load(int seconds) {
  const auto deadline = std::chrono::steady_clock::now() +
                        std::chrono::seconds(seconds);
  const unsigned int count = std::max(1u, std::thread::hardware_concurrency());
  std::vector<std::thread> workers;
  workers.reserve(count);

  for (unsigned int i = 0; i < count; ++i) {
    workers.emplace_back([i, deadline]() {
      volatile unsigned long long value = i + 1;
      while (std::chrono::steady_clock::now() < deadline) {
        value = value * 1664525ULL + 1013904223ULL;
      }
    });
  }
  for (auto& worker : workers) worker.join();
}

}  // namespace

int main(int argc, char* argv[]) {
  int port = 5000;
  for (int i = 1; i < argc; ++i) {
    if (std::strcmp(argv[i], "-port") == 0 && i + 1 < argc) {
      port = std::atoi(argv[++i]);
    } else {
      std::cerr << "Usage: " << argv[0] << " [-port PORT]\n";
      return 1;
    }
  }
  if (port < 1 || port > 65535) {
    std::cerr << "Port must be between 1 and 65535\n";
    return 1;
  }

  const int server = socket(AF_INET, SOCK_STREAM, 0);
  if (server < 0) {
    perror("socket");
    return 1;
  }
  int reuse = 1;
  setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));

  sockaddr_in address{};
  address.sin_family = AF_INET;
  address.sin_port = htons(port);
  inet_pton(AF_INET, "127.0.0.1", &address.sin_addr);
  if (bind(server, reinterpret_cast<sockaddr*>(&address), sizeof(address)) < 0 ||
      listen(server, 8) < 0) {
    perror("bind/listen");
    close(server);
    return 1;
  }

  std::cout << "test_app listening on http://127.0.0.1:" << port << std::endl;
  while (true) {
    const int client = accept(server, nullptr, nullptr);
    if (client < 0) {
      perror("accept");
      continue;
    }

    char request[2048]{};
    const ssize_t received = recv(client, request, sizeof(request) - 1, 0);
    if (received <= 0) {
      close(client);
      continue;
    }

    std::istringstream line(request);
    std::string method, target, version;
    line >> method >> target >> version;
    if (method != "GET") {
      send_response(client, 405, "Method Not Allowed", "GET only\n");
    } else if (target == "/health") {
      send_response(client, 200, "OK", "ok\n");
    } else if (target == "/cpu" || target.rfind("/cpu?seconds=", 0) == 0) {
      int seconds = 120;
      const std::string prefix = "/cpu?seconds=";
      if (target.rfind(prefix, 0) == 0) {
        char* end = nullptr;
        const long parsed = std::strtol(target.c_str() + prefix.size(), &end, 10);
        if (end == target.c_str() + prefix.size() || parsed < 1 || parsed > 120) {
          send_response(client, 400, "Bad Request", "seconds must be 1..120\n");
          close(client);
          continue;
        }
        seconds = static_cast<int>(parsed);
      }
      create_cpu_load(seconds);
      send_response(client, 200, "OK", "CPU workload completed: " +
                                             std::to_string(seconds) + " seconds\n");
    } else {
      send_response(client, 404, "Not Found", "Use /health or /cpu\n");
    }
    close(client);
  }

  close(server);
  return 0;
}
