#include "../include/MetricsExporter.h"

#include <string>
#include <utility>
#include <vector>
#include <iostream>
#include <sstream>
#include <unistd.h>
#include <netinet/in.h>
#include <thread>
#include <chrono>
#include <cstring>
#include <random>
#include <ranges>
#include <sys/socket.h>

shared_ptr<unordered_map<uint32_t, Crawler>> crawler_;

void [[noreturn]] MetricsExporter::serve(shared_ptr<unordered_map<uint32_t, Crawler>> crawler) {
    crawler_ = move(crawler);

    // server_fd is a file descriptor.
    const int server_fd = socket(AF_INET, SOCK_STREAM, 0);

    sockaddr_in addr{};
    addr.sin_family = AF_INET;
    addr.sin_port = htons(8889);
    addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(server_fd, reinterpret_cast<sockaddr *>(&addr), sizeof(addr)) != 0) {
        cout << "Please wait for the pipe to close.";
        return;
    }

    listen(server_fd, 50);

    cout << "Exporter is running on http://localhost:8889 \n";

    while (true) {
        int client_fd = accept(server_fd, nullptr, nullptr);

        thread(process_request, client_fd).detach();
    }

    close(server_fd);
}

void MetricsExporter::process_request(const int client_fd) {
    ostringstream oss;

    oss << HEAD;

    int total = 0;

    for (const auto &[user_agent, links_pressed]: *crawler_ | views::values) {
        total += links_pressed;
    }

    oss << "# HELP links_pressed_total Total number of links pressed.\n";
    oss << "# TYPE links_pressed_total counter\n";
    oss << "links_pressed_total " << total << "\n";

    send(client_fd, oss.str().c_str(), oss.str().size(), 0);
    close(client_fd);
}