/*
** Job Arranger for ZABBIX
** Copyright (C) 2025 Daiwa Institute of Research Ltd. All Rights Reserved.
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
**/
package main

/*
typedef struct {
	char *parameter;
	void *variable;
	int	data_type;
	size_t max_size;
} cfg_line;
*/
import "C"

import (
	"fmt"
	"os"
	"reflect"
	"unsafe"

	"jobarranger2/src/libs/golibs/config_reader/agent"
	"jobarranger2/src/libs/golibs/config_reader/conf"
	"jobarranger2/src/libs/golibs/config_reader/server"
)

//export LoadConfigForC
func LoadConfigForC(configPath *C.char, cfg *C.cfg_line, cfgCount C.int, target C.int) C.int {
	goConfigPath := C.GoString(configPath)

	var goOpts any

	if target == 0 {
		goOpts = &server.ServerOptions{}
	} else if target == 1 {
		goOpts = &agent.AgentOptions{}
	} else {
		fmt.Fprint(os.Stderr, "Invalid target [0:server, 1:agent]\n")
		return -1
	}

	err := conf.Load(goConfigPath, goOpts)
	if err != nil {
		// Error message
		fmt.Fprintf(os.Stderr, "Failed to load config: %s\n", err.Error())
		return -1
	}

	// sanity check for bound
	if cfgCount <= 0 || cfgCount > 1e6 {
		return -1
	}

	cfgSlice := (*[1 << 30]C.cfg_line)(unsafe.Pointer(cfg))[:cfgCount:cfgCount]
	// Get value of go options
	val := reflect.ValueOf(goOpts).Elem()

	for _, item := range cfgSlice {
		paramName := C.GoString(item.parameter)

		// Check if the param passed from C is valid
		field := val.FieldByName(paramName)
		if !field.IsValid() {
			fmt.Fprintf(os.Stderr, "field is not valid: %s\n", paramName)
			return -1
		}

		// Assign value to pointers based on the data type from C
		switch item.data_type {
		// Int type
		case 0:
			if field.Kind() == reflect.Int {
				*(*C.int)(item.variable) = C.int(field.Int())
			} else {
				fmt.Fprintf(os.Stderr, "type mismatched for '%s'\n", paramName)
				return -1
			}
		// String type
		case 1:
			if field.Kind() == reflect.String {
				str := field.String()
				if str != "" {
					maxSize := item.max_size
					if maxSize > 0 {
						// Copy string directly into C's buffer
						strBytes := []byte(str)
						maxLen := int(maxSize) - 1

						// Check for overflow
						if len(strBytes) > maxLen {
							strBytes = strBytes[:maxLen]
						}

						// Write to C memory
						dst := unsafe.Slice((*byte)(item.variable), maxSize)
						copy(dst, strBytes)

						// Null-terminate
						dst[len(strBytes)] = 0

					}
				}
			} else {
				fmt.Fprintf(os.Stderr, "type mismatched for '%s'\n", paramName)
				return -1
			}
		default:
			fmt.Fprintf(os.Stderr, "unsupported data type for parameter '%s'\n", paramName)
			return -1
		}

	}

	return 0

}

func main() {}
