/*
 * network.cpp
 * TLS fetch, daily-feature fetch, and article search for the Wikipedia client
 * Copyright (c) 2026 Daniel Hammer
 */

#include "wikipedia.h"

int wiki_fetch(const char* path, char* respBuf, int respMax) {
    static char request[2560];
    int reqLen = snprintf(request, sizeof(request),
        "GET %s HTTP/1.0\r\n"
        "Host: %s\r\n"
        "User-Agent: MontaukOS/1.0 wikipedia\r\n"
        "Accept: application/json\r\n"
        "Connection: close\r\n"
        "\r\n",
        path, WIKI_HOST);
    return tls::https_fetch(WIKI_HOST, g_server_ip, 443,
                            request, reqLen, g_tas,
                            respBuf, respMax);
}

bool ensure_wiki_tls_ready(char* err, int err_len) {
    if (!g_tls_ready) {
        g_server_ip = montauk::resolve(WIKI_HOST);
        if (g_server_ip == 0) {
            if (err && err_len > 0)
                snprintf(err, err_len, "Error: could not resolve en.wikipedia.org");
            return false;
        }
        g_tas = tls::load_trust_anchors();
        if (g_tas.count == 0) {
            if (err && err_len > 0)
                snprintf(err, err_len, "Error: no CA certificates loaded");
            return false;
        }
        g_tls_ready = true;
    }
    return true;
}

bool welcome_feed_path(char* path, int path_len) {
    Montauk::DateTime dt {};
    montauk::gettime(&dt);

    if (dt.Year < 2001 || dt.Month < 1 || dt.Month > 12 ||
        dt.Day < 1 || dt.Day > 31) {
        snprintf(g_welcome_status, sizeof(g_welcome_status),
                 "Daily featured article unavailable until the system date is set.");
        return false;
    }

    snprintf(g_welcome_date, sizeof(g_welcome_date),
             "%04u-%02u-%02u",
             (unsigned)dt.Year, (unsigned)dt.Month, (unsigned)dt.Day);
    snprintf(path, path_len,
             "/api/rest_v1/feed/featured/%04u/%02u/%02u",
             (unsigned)dt.Year, (unsigned)dt.Month, (unsigned)dt.Day);
    return true;
}

void do_welcome_fetch() {
    char err[192] = {};
    if (!ensure_wiki_tls_ready(err, sizeof(err))) {
        snprintf(g_welcome_status, sizeof(g_welcome_status), "%s", err);
        build_welcome_lines(true);
        return;
    }

    static char path[128];
    if (!welcome_feed_path(path, sizeof(path))) {
        build_welcome_lines(true);
        return;
    }

    int respLen = wiki_fetch(path, g_resp_buf, RESP_MAX);
    if (respLen <= 0) {
        snprintf(g_welcome_status, sizeof(g_welcome_status),
                 "Daily featured article unavailable; search is ready.");
        build_welcome_lines(true);
        return;
    }
    g_resp_buf[respLen] = '\0';

    int headerEnd = find_header_end(g_resp_buf, respLen);
    if (headerEnd < 0) {
        snprintf(g_welcome_status, sizeof(g_welcome_status),
                 "Daily featured article unavailable; search is ready.");
        build_welcome_lines(true);
        return;
    }

    int status = parse_status_code(g_resp_buf, headerEnd);
    const char* body = g_resp_buf + headerEnd;
    int bodyLen = respLen - headerEnd;
    if (status < 200 || status >= 300) {
        snprintf(g_welcome_status, sizeof(g_welcome_status),
                 "Daily featured article unavailable; search is ready.");
        build_welcome_lines(true);
        return;
    }

    int tfa = find_substr(body, bodyLen, "\"tfa\"");
    if (tfa < 0) {
        snprintf(g_welcome_status, sizeof(g_welcome_status),
                 "Daily featured article unavailable; search is ready.");
        build_welcome_lines(true);
        return;
    }

    int tfaLen = bodyLen - tfa;
    extract_json_string(body + tfa, tfaLen, "title",
                        g_welcome_feature_title,
                        sizeof(g_welcome_feature_title));
    extract_json_string(body + tfa, tfaLen, "extract",
                        g_welcome_feature_extract,
                        sizeof(g_welcome_feature_extract));

    underscores_to_spaces(g_welcome_feature_title);
    g_welcome_feature_loaded = g_welcome_feature_title[0] != '\0';
    if (g_welcome_feature_loaded)
        g_welcome_status[0] = '\0';
    else
        snprintf(g_welcome_status, sizeof(g_welcome_status),
                 "Daily featured article unavailable; search is ready.");

    build_welcome_lines(true);
}

void do_search(const char* query) {
    if (is_main_page_query(query)) {
        g_phase = AppPhase::WELCOME;
        build_welcome_lines(false);
        return;
    }

    if (!ensure_wiki_tls_ready(g_status, sizeof(g_status))) {
        g_phase = AppPhase::ERR;
        return;
    }

    static char encoded[1024];
    url_encode_title(query, encoded, sizeof(encoded));

    static char path[2048];
    snprintf(path, sizeof(path),
        "/w/api.php?action=query&format=json&formatversion=2"
        "&prop=extracts&explaintext=1&titles=%s", encoded);

    int respLen = wiki_fetch(path, g_resp_buf, RESP_MAX);
    if (respLen <= 0) {
        snprintf(g_status, sizeof(g_status), "Error: no response from Wikipedia");
        g_phase = AppPhase::ERR; return;
    }
    g_resp_buf[respLen] = '\0';

    int headerEnd = find_header_end(g_resp_buf, respLen);
    if (headerEnd < 0) {
        snprintf(g_status, sizeof(g_status), "Error: malformed HTTP response");
        g_phase = AppPhase::ERR; return;
    }

    int status      = parse_status_code(g_resp_buf, headerEnd);
    const char* body = g_resp_buf + headerEnd;
    int bodyLen     = respLen - headerEnd;

    if (status == 404) {
        snprintf(g_status, sizeof(g_status), "Article not found: %s", query);
        g_phase = AppPhase::ERR; return;
    }

    extract_json_string(body, bodyLen, "title", g_title, sizeof(g_title));
    g_extract_len = extract_json_string(body, bodyLen, "extract",
                                        g_extract_buf, RESP_MAX - 1);
    if (g_extract_len == 0) {
        snprintf(g_status, sizeof(g_status), "No content found for: %s", query);
        g_phase = AppPhase::ERR; return;
    }

    build_display_lines(g_title, g_extract_buf, g_extract_len);
    g_phase = AppPhase::DONE;
}
