package misc

import (
	"fmt"
	"reflect"
	"sort"
	"strconv"
)

func StructToMap(obj interface{}) map[string]string {
	result := make(map[string]string)
	v := reflect.ValueOf(obj)
	t := reflect.TypeOf(obj)

	for i := 0; i < v.NumField(); i++ {
		fieldName := t.Field(i).Name
		fieldValue := v.Field(i)

		// Convert value to string
		var valueStr string
		switch fieldValue.Kind() {
		case reflect.String:
			valueStr = fieldValue.String()
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			valueStr = strconv.FormatInt(fieldValue.Int(), 10)
		case reflect.Float32, reflect.Float64:
			valueStr = strconv.FormatFloat(fieldValue.Float(), 'f', -1, 64)
		case reflect.Bool:
			valueStr = strconv.FormatBool(fieldValue.Bool())
		default:
			valueStr = fmt.Sprintf("%v", fieldValue.Interface())
		}

		result[fieldName] = valueStr
	}
	return result
}

func StructFields(obj interface{}) []string {
	var result []string
	t := reflect.TypeOf(obj)
	for i := 0; i < t.NumField(); i++ {
		fieldName := t.Field(i).Name
		result = append(result, fieldName)
	}
	sort.Strings(result)
	return result
}

func MapToStruct(m map[string]string, result interface{}) error {
	v := reflect.ValueOf(result).Elem() // Get the pointer to the struct

	for key, value := range m {
		field := v.FieldByName(key) // Get struct field by name

		if !field.IsValid() {
			continue // Skip if field doesn't exist
		}

		if !field.CanSet() {
			continue // Skip unexported fields
		}

		switch field.Kind() {
		case reflect.String:
			field.SetString(value)
		case reflect.Int, reflect.Int64:
			intVal, err := strconv.Atoi(value)
			if err != nil {
				return fmt.Errorf("failed to convert %s to int: %v", key, err)
			}
			field.SetInt(int64(intVal))
		default:
			return fmt.Errorf("unsupported field type: %s", field.Kind())
		}
	}
	return nil
}
