//go:build cgo && native_libs
// +build cgo,native_libs

package worker

// #cgo darwin LDFLAGS: -L${SRCDIR}/../../native/build -Wl,-rpath,${SRCDIR}/../../native/build -ldataset_hash
// #cgo linux LDFLAGS: -L${SRCDIR}/../../native/build -Wl,-rpath,${SRCDIR}/../../native/build -ldataset_hash -lnvml_gpu -lnvidia-ml
// #include "../../native/dataset_hash/dataset_hash.h"
// #include <stdlib.h>
import "C"

import (
	"errors"
	"log"
	"runtime"
	"sync"
	"time"
	"unsafe"

	"github.com/jfraeys/fetch_ml/internal/manifest"
)

var (
	hashCtx     *C.fh_context_t
	hashCtxOnce sync.Once
	ctxInitTime time.Time
)

// getHashContext returns the native hash context, initializing it on first call.
// First call initializes C++ context (5-20ms) - subsequent calls reuse context.
func getHashContext() *C.fh_context_t {
	hashCtxOnce.Do(func() {
		start := time.Now()
		hashCtx = C.fh_init(C.uint32_t(runtime.NumCPU()))
		ctxInitTime = time.Now()
		log.Printf("[native] hash context initialized: %v (threads: %d)",
			time.Since(start), runtime.NumCPU())
	})
	return hashCtx
}

func dirOverallSHA256HexNative(root string) (string, error) {
	ctx := getHashContext()

	croot := C.CString(root)
	defer C.free(unsafe.Pointer(croot))

	result := C.fh_hash_directory_combined(ctx, croot)
	if result == nil {
		err := C.fh_last_error(ctx)
		if err != nil {
			return "", errors.New(C.GoString(err))
		}
		return "", errors.New("native hash failed")
	}
	defer C.fh_free_string(result)

	return C.GoString(result), nil
}

func GetSIMDImplName() string {
	return C.GoString(C.fh_get_simd_impl_name())
}

func HasSIMDSHA256() bool {
	return C.fh_has_simd_sha256() == 1
}

func ScanArtifactsNative(runDir string) (*manifest.Artifacts, error) {
	return ScanArtifacts(runDir, false, nil)
}

func ExtractTarGzNative(archivePath, dstDir string) error {
	return ExtractTarGz(archivePath, dstDir)
}

// DirOverallSHA256HexNative exports the native hash implementation for benchmarks.
func DirOverallSHA256HexNative(root string) (string, error) {
	return dirOverallSHA256HexNative(root)
}
