// rsrcProbe.c - Phase 3.4 real Resource Manager smoke probe.
//
// Replaces the stub-only probe.  Builds a tiny in-memory .rsrc fixture,
// registers it with mfsRegister, opens it via openResourceFile, loads
// a known rText resource, and verifies the bytes match the expected
// payload.  This exercises the real parser path top-to-bottom without
// needing a ProDOS resource fork.
//
// Markers (page-1 direct page, per cursorProbe convention):
//   $70 := 0x99   end-of-main success sentinel
//   $71 := 0x01   if openResourceFile succeeded (refnum != 0)
//   $72 := 0x01   if loadResource returned a non-NULL handle whose
//                 bytes match "HELLO" and size is 5
//   $73 := 0x01   if loadResource second call returned the SAME handle
//                 (cache hit) and closeResourceFile returned RES_OK
//
// Build:   bash demos/build.sh rsrcProbe
// Run:     bash scripts/runViaFinder.sh demos/rsrcProbe.omf \
//              --check 0x70=0x99 0x71=0x01 0x72=0x01 0x73=0x01

#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "iigs/resource.h"


// rResourceMap fixture: header + 5-byte rText payload + one rIndex entry.
//
// Header (24 bytes, little-endian):
//   rmVersion       = 0x0000
//   rmToIndex       = 0x0000001D (29)
//   rmFileNum       = 0
//   rmID            = 0
//   rmIndexSize     = 0x00000014 (20 bytes = 1 entry)
//   rmIndexUsed     = 0x00000001
//   rmFreeListSize  = 0
//   rmFreeListUsed  = 0
//   rmPad           = 0
// Payload (5 bytes) at offset 24:  "HELLO"
// rIndex entry (20 bytes) at offset 29:
//   rType   = 0x8014  (rText)
//   rID     = 0x00000001
//   rOffset = 0x00000018  (24)
//   rAttr   = 0
//   rSize   = 0x00000005
//   rHandle = 0
static const uint8_t kFixture[49] = {
    // header
    0x00, 0x00,                             // rmVersion
    0x1D, 0x00, 0x00, 0x00,                 // rmToIndex = 29
    0x00, 0x00,                             // rmFileNum
    0x00, 0x00,                             // rmID
    0x14, 0x00, 0x00, 0x00,                 // rmIndexSize = 20
    0x01, 0x00, 0x00, 0x00,                 // rmIndexUsed = 1
    0x00, 0x00,                             // rmFreeListSize
    0x00, 0x00,                             // rmFreeListUsed
    0x00, 0x00,                             // rmPad
    // payload at offset 24: "HELLO"
    0x48, 0x45, 0x4C, 0x4C, 0x4F,
    // rIndex entry at offset 29
    0x14, 0x80,                             // rType = 0x8014
    0x01, 0x00, 0x00, 0x00,                 // rID = 1
    0x18, 0x00, 0x00, 0x00,                 // rOffset = 24
    0x00, 0x00,                             // rAttr
    0x05, 0x00, 0x00, 0x00,                 // rSize = 5
    0x00, 0x00, 0x00, 0x00                  // rHandle
};


static const char     kFixturePath[]   = "rsrc.fixture";
static const char     kExpectedText[]  = "HELLO";
static const uint32_t kExpectedSize    = 5;


int main(void) {
    volatile uint8_t *mark0 = (volatile uint8_t *)0x70;
    volatile uint8_t *mark1 = (volatile uint8_t *)0x71;
    volatile uint8_t *mark2 = (volatile uint8_t *)0x72;
    volatile uint8_t *mark3 = (volatile uint8_t *)0x73;

    *mark0 = 0x10;
    *mark1 = 0x00;
    *mark2 = 0x00;
    *mark3 = 0x00;

    // Stage the fixture as a read-only memory-backed file.  Cast away
    // const for the mfsRegister buffer pointer; the resource manager
    // only ever reads.
    if (mfsRegister(kFixturePath, (void *)kFixture, sizeof(kFixture), sizeof(kFixture), 0) != 0) {
        while (1) {
        }
    }

    resourceProbeInit();

    int rcOpen = 0;
    ResourceRefNumT ref = openResourceFile(kFixturePath, 0, 0, &rcOpen);
    if (ref != 0 && rcOpen == RES_OK) {
        *mark1 = 0x01;
    }

    int rcLoad = 0;
    void **h = loadResource(RES_TYPE_RTEXT, 1, &rcLoad);
    if (h && rcLoad == RES_OK) {
        const uint8_t *bytes = (const uint8_t *)*h;
        uint32_t sz          = getResourceSize(h);
        int match            = (sz == kExpectedSize);
        if (match) {
            for (uint32_t i = 0; i < kExpectedSize; i++) {
                if (bytes[i] != (uint8_t)kExpectedText[i]) {
                    match = 0;
                    break;
                }
            }
        }
        if (match) {
            *mark2 = 0x01;
        }
    }

    // Second load - cache hit must return the SAME handle.  Then
    // close the file, which must report RES_OK.
    int   rcLoad2 = 0;
    void **h2     = loadResource(RES_TYPE_RTEXT, 1, &rcLoad2);
    int   sameHandle = (h2 == h && h2 != 0);
    int   rcClose    = closeResourceFile(ref);
    if (sameHandle && rcClose == RES_OK) {
        *mark3 = 0x01;
    }

    *mark0 = 0x99;

    while (1) {
    }
    return 0;
}
