#include "http.hpp"
#include "tls_server.hpp"

#include <algorithm>
#include <chrono>
#include <cstdio>
#include <cstring>
#include <ctime>

// ---------------------------------------------------------------------------
// HttpRequest
// ---------------------------------------------------------------------------

std::string HttpRequest::get_query_param(const std::string& key, const std::string& def) const {
    std::string needle = key + "=";
    size_t pos = query_string.find(needle);
    if (pos == std::string::npos) return def;

    size_t val_start = pos + needle.size();
    size_t val_end = query_string.find('&', val_start);
    if (val_end == std::string::npos) val_end = query_string.size();

    std::string raw = query_string.substr(val_start, val_end - val_start);

    // Simple URL decode
    std::string decoded;
    decoded.reserve(raw.size());
    for (size_t i = 0; i < raw.size(); ++i) {
        if (raw[i] == '%' && i + 2 < raw.size()) {
            char hex[3] = { raw[i+1], raw[i+2], 0 };
            decoded += static_cast<char>(std::strtol(hex, nullptr, 16));
            i += 2;
        } else if (raw[i] == '+') {
            decoded += ' ';
        } else {
            decoded += raw[i];
        }
    }
    return decoded;
}

// ---------------------------------------------------------------------------
// HttpResponse
// ---------------------------------------------------------------------------

void HttpResponse::send_json(int code, const json& body) {
    if (headers_sent) return;
    status_code = code;

    std::string body_str = body.dump();
    body_for_log = body_str;
    std::string resp = "HTTP/1.1 " + std::to_string(code) + " " + reason_phrase(code) + "\r\n"
        "Content-Type: application/json; charset=utf-8\r\n"
        "Content-Length: " + std::to_string(body_str.size()) + "\r\n"
        "Connection: keep-alive\r\n"
        "\r\n"
        + body_str;

    session_write(session, resp);
    headers_sent = true;
}

void HttpResponse::send_binary(int code, const std::vector<uint8_t>& data, const std::string& content_type) {
    if (headers_sent) return;
    status_code = code;

    std::string header = "HTTP/1.1 " + std::to_string(code) + " " + reason_phrase(code) + "\r\n"
        "Content-Type: " + content_type + "\r\n"
        "Content-Length: " + std::to_string(data.size()) + "\r\n"
        "Connection: keep-alive\r\n"
        "\r\n";

    session_write_binary(session, header, data);
    headers_sent = true;
}

void HttpResponse::send_empty(int code) {
    if (headers_sent) return;
    status_code = code;

    std::string resp = "HTTP/1.1 " + std::to_string(code) + " " + reason_phrase(code) + "\r\n"
        "Content-Length: 0\r\n"
        "Connection: keep-alive\r\n"
        "\r\n";

    session_write(session, resp);
    headers_sent = true;
}

void HttpResponse::finish() {
    // Connection keep-alive: don't close after each request.
}

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

std::string normalize_path(const std::string& pathname) {
    // /api/v1/... -> /v1/...
    const std::string prefix = "/api";
    if (pathname.size() >= prefix.size() &&
        pathname.compare(0, prefix.size(), prefix) == 0) {
        if (pathname.size() > prefix.size() && pathname[prefix.size()] == '/' &&
            pathname.size() > prefix.size() + 1 &&
            pathname.compare(prefix.size() + 1, 2, "v1") == 0) {
            return pathname.substr(prefix.size());
        }
    }
    return pathname;
}

std::string server_timestamp() {
    auto now = std::chrono::system_clock::now();
    std::time_t t = std::chrono::system_clock::to_time_t(now);
    std::tm tm_buf{};
    localtime_r(&t, &tm_buf);

    char buf[32];
    std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm_buf);
    return buf;
}
