// The MIT License (MIT)
//
// Copyright (C) 2026 Scott Duensing
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

// basBuild.c -- shared "emit .app resource set" step
//
// See basBuild.h for the public contract.  This file used to live inline
// in two places: ideMain.c (the IDE's Make Executable path) and
// bascomp.c (the standalone command-line compiler).  Both implementations
// were essentially identical, so they are now consolidated here.
//
// The canonical emit order is:
//   1. BAS_RES_NAME                (always, falls back to "BASIC App")
//   2. BAS_RES_AUTHOR / PUBLISHER / VERSION / COPYRIGHT / DESCRIPTION
//      (each skipped if empty)
//   3. BAS_RES_ICON32              (file via iconPath, else iconData bytes)
//   4. BAS_RES_HELPFILE            (filename only, if helpFile set)
//   5. BAS_RES_MODULE              (bytecode)
//   6. BAS_RES_DEBUG               (optional)
//   7. FORM0, FORM1, ...           (one per spec->formCount)

#include "basBuild.h"
#include "basRes.h"
#include "../../../libs/kpunch/libdvx/dvxRes.h"
#include "../../../libs/kpunch/libdvx/platform/dvxPlat.h"

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


// ------------------------------------------------------------
// Internal helpers
// ------------------------------------------------------------


static void appendText(const char *path, const char *name, const char *value) {
    if (!value || !value[0]) {
        return;
    }

    dvxResAppend(path, name, DVX_RES_TEXT, value, (uint32_t)strlen(value) + 1);
}


static void emitIcon(const char *path, const BasBuildSpecT *spec) {
    // If a disk path was given, load it and embed.  Otherwise use the
    // pre-loaded bytes (used by the IDE for its "noicon" fallback).
    if (spec->iconPath && spec->iconPath[0]) {
        int32_t iconLen = 0;
        char   *iconData = platformReadFile(spec->iconPath, &iconLen);

        if (iconData) {
            dvxResAppend(path, BAS_RES_ICON32, DVX_RES_ICON, iconData, (uint32_t)iconLen);
            free(iconData);
        }

        return;
    }

    if (spec->iconData && spec->iconSize > 0) {
        dvxResAppend(path, BAS_RES_ICON32, DVX_RES_ICON, spec->iconData, (uint32_t)spec->iconSize);
    }
}


// ------------------------------------------------------------
// Public API
// ------------------------------------------------------------


int32_t basBuildEmitResources(const char *outPath, const BasBuildSpecT *spec) {
    if (!outPath || !spec) {
        return -1;
    }

    // Project metadata.  Name is required -- fall back to a generic label
    // so the compiled app always has something sensible to display.
    const char *projName = (spec->projName && spec->projName[0]) ? spec->projName : "BASIC App";
    appendText(outPath, BAS_RES_NAME, projName);

    appendText(outPath, BAS_RES_AUTHOR,      spec->author);
    appendText(outPath, BAS_RES_PUBLISHER,   spec->publisher);
    appendText(outPath, BAS_RES_VERSION,     spec->version);
    appendText(outPath, BAS_RES_COPYRIGHT,   spec->copyright);
    appendText(outPath, BAS_RES_DESCRIPTION, spec->description);

    // Icon.
    emitIcon(outPath, spec);

    // Help file name (just the basename -- stub resolves it next to the app).
    if (spec->helpFile && spec->helpFile[0]) {
        const char *helpBase = platformPathBaseName(spec->helpFile);
        appendText(outPath, BAS_RES_HELPFILE, helpBase);
    }

    // Bytecode module.
    if (spec->moduleData && spec->moduleLen > 0) {
        dvxResAppend(outPath, BAS_RES_MODULE, DVX_RES_BINARY, spec->moduleData, (uint32_t)spec->moduleLen);
    }

    // Optional debug info.
    if (spec->debugData && spec->debugLen > 0) {
        dvxResAppend(outPath, BAS_RES_DEBUG, DVX_RES_BINARY, spec->debugData, (uint32_t)spec->debugLen);
    }

    // Form resources.  Callers pre-strip / pre-obfuscate as needed; we just
    // write them out as FORM0, FORM1, ...
    for (int32_t i = 0; i < spec->formCount; i++) {
        if (!spec->formData || !spec->formData[i] || !spec->formLens || spec->formLens[i] <= 0) {
            continue;
        }

        char resName[16];
        snprintf(resName, sizeof(resName), "FORM%ld", (long)i);
        dvxResAppend(outPath, resName, DVX_RES_BINARY, spec->formData[i], (uint32_t)spec->formLens[i]);
    }

    return 0;
}
