// cxxStreamProbe.cpp - exercise the C++ stream + format + path surface
// (Phase 5.4).  Probes the cout-replacement pattern:
//
//   1. etl::string_stream<<int composing into a fixed-capacity buffer.
//   2. etl::format_to(buf, "{}", 42) — the std::format substitute (gated
//      behind CXX_STREAM_PROBE_WITH_FORMAT; pulls ~50 KB of format
//      machinery — see step 5 size spike below).
//   3. iigs::path::pathJoin + pathSplit + pathNormalize on a ProDOS-style
//      colon-separated path.
//   4. Compile-time contract that etl::chrono::*_clock::duration::rep is
//      int32_t (the i64-libcall guard from etl_profile.h).
//
// Build flavors:
//   default                                : path + string_stream + chrono
//                                            contract.  Single-bank bin.
//   GNO_CFLAGS=-DCXX_STREAM_PROBE_WITH_FORMAT=1
//                                          : adds etl::format_to probe.
//                                            Pulls in parse_format_spec /
//                                            vformat_to / per-type
//                                            format_aligned_int /
//                                            format_alternate_form —
//                                            total ~50 KB delta over the
//                                            no-format flavor, crosses
//                                            bank-0 IO window.  Requires
//                                            multi-seg or --layer2 link.
//                                            Phase 5.4 step 5 size-spike
//                                            outcome: downgrade scope
//                                            (FP-format / full format
//                                            are layer2-opt-in, not the
//                                            default).
//
// Marker layout (16-bit little-endian at $025xxx):
//   $025010 = 0xBEEF  main entered
//   $025012 = etl::chrono::steady_clock duration rep is i32 sentinel (1/0)
//   $025014 = string_stream emitted expected string (1/0)
//   $025016 = etl::format_to emitted expected string (1/0; sentinel 1
//             when format probe gated off)
//   $025018 = pathJoin("USR", "BIN") => "USR:BIN" check (1/0)
//   $02501A = pathNormalize("USR::BIN::..::LIB") => "USR:LIB" check (1/0)
//   $02501C = pathSplit("USR:BIN:LS") => parent="USR:BIN" + leaf="LS" (1/0)
//   $02501E = pathJoin rejects 65-char component (1 = correctly rejected)
//   $025020 = pathNormalize rejects 9-deep path (1 = correctly rejected)
//   $025000 = 0xC0DE  reached end-of-main (sentinel for runInGno --check)
#include <stdint.h>

#include <iigs/path.h>
#include <sstream>
#include "etl/chrono.h"
#include "etl/string.h"
#include "etl/string_stream.h"
#include "etl/string_view.h"
#include "etl/to_string.h"

#ifdef CXX_STREAM_PROBE_WITH_FORMAT
#include "etl/format.h"
#endif


static uint16_t streq(const char *a, const char *b) {
    while (*a && *b) {
        if (*a != *b) {
            return 0;
        }
        a++;
        b++;
    }
    return (uint16_t)((*a == 0 && *b == 0) ? 1 : 0);
}


int main(void) {
    *(volatile uint16_t *)0x025010UL = 0xBEEF;

    // Compile-time contract: clock-rep stays i32 (etl_profile.h override).
    // Avoids i64 chrono libcalls in stream + format demos.
    static_assert(sizeof(etl::chrono::steady_clock::duration::rep) == 4,
                  "etl::chrono::steady_clock::rep must be i32 -- check "
                  "ETL_CHRONO_STEADY_CLOCK_DURATION in etl_profile.h");
    *(volatile uint16_t *)0x025012UL = 1;

    // ---- (1) etl::string_stream << int ------------------------------
    // Flattened layout (no nested {}-scopes) — the bracketed-scope form
    // tripped a W65816 Wide32->2xi16 lowering bug on three nested
    // etl::string<32> stack allocations.  Sequential single-string use
    // works fine and is the documented cout-replacement idiom.
    {
        etl::string<32> streamBuf;
        etl::string_stream ss(streamBuf);
        ss << "x=" << 42;
        {
            etl::string<32> tmp;
            etl::string_stream ssTmp(tmp);
            ssTmp << "y=" << 7;
            {
                etl::string<32> third;
                etl::string_stream ss3(third);
                ss3 << "z=" << 3;
                *(volatile uint16_t *)0x025014UL = streq(ss3.str().c_str(), "z=3");
            }
        }
    }

    // ---- (2) etl::format_to(buf, "{}", 42) --------------------------
#ifdef CXX_STREAM_PROBE_WITH_FORMAT
    etl::string<32> formatBuf;
    etl::format_to(formatBuf, "{}", 42);
    *(volatile uint16_t *)0x025016UL = streq(formatBuf.c_str(), "42");
#else
    // Sentinel: format probe gated off in single-bank flavor.  See
    // docs/GAP_CLOSURE_PLAN.md Phase 5.4 step 5 (size spike >10 KB
    // delta -- explicit downgrade to layer2-opt-in).
    *(volatile uint16_t *)0x025016UL = 1;
#endif

    // ---- (3a) pathJoin -----------------------------------------------
    char joinOut[64];
    bool joinOk = iigs::path::pathJoin("USR", "BIN", joinOut, sizeof(joinOut));
    *(volatile uint16_t *)0x025018UL =
        (uint16_t)((joinOk && streq(joinOut, "USR:BIN")) ? 1 : 0);

    // ---- (3b) pathNormalize collapsing & .. ---------------------------
    char normOut[64];
    bool normOk = iigs::path::pathNormalize("USR::BIN::..::LIB",
                                            normOut, sizeof(normOut));
    *(volatile uint16_t *)0x02501AUL =
        (uint16_t)((normOk && streq(normOut, "USR:LIB")) ? 1 : 0);

    // ---- (3c) pathSplit -----------------------------------------------
    char splitParent[64];
    char splitLeaf[64];
    bool splitOk = iigs::path::pathSplit("USR:BIN:LS",
                                         splitParent, sizeof(splitParent),
                                         splitLeaf, sizeof(splitLeaf));
    *(volatile uint16_t *)0x02501CUL =
        (uint16_t)((splitOk && streq(splitParent, "USR:BIN") &&
                    streq(splitLeaf, "LS")) ? 1 : 0);

    // ---- (3d) 65-char component rejection -----------------------------
    char bigName[80];
    for (uint16_t i = 0; i < 65; i++) {
        bigName[i] = 'A';
    }
    bigName[65] = 0;
    char bigOut[128];
    bool bigRejected = !iigs::path::pathJoin("USR", bigName, bigOut, sizeof(bigOut));
    *(volatile uint16_t *)0x02501EUL = (uint16_t)(bigRejected ? 1 : 0);

    // ---- (3e) 9-deep path rejection -----------------------------------
    char deepOut[128];
    bool deepRejected = !iigs::path::pathNormalize(
        "A:B:C:D:E:F:G:H:I", deepOut, sizeof(deepOut));
    *(volatile uint16_t *)0x025020UL = (uint16_t)(deepRejected ? 1 : 0);

    *(volatile uint16_t *)0x025000UL = 0xC0DE;
    return 0;
}
