package store

import (
	"encoding/json"
	"os"
	"path/filepath"

	"code.fbi.h-da.de/danet/gosdn/controller/config"
	"code.fbi.h-da.de/danet/gosdn/controller/customerrs"
	"github.com/google/uuid"
	log "github.com/sirupsen/logrus"
)

// FromString is a helper to check if a provided string as a valid UUID or a name.
func FromString(id string) (uuid.UUID, error) {
	idAsUUID, err := uuid.Parse(id)

	// id is no UUID therefore it could be a network element name.
	// The name will be returned within the error.
	if err != nil {
		log.WithFields(log.Fields{
			"identifier": id,
		}).Debug(err)
		return uuid.Nil, &customerrs.InvalidUUIDError{NetworkElementName: id}
	}

	return idAsUUID, nil
}

// EnsureFilesystemStorePathExists ensures that the filesystem store path exists.
func EnsureFilesystemStorePathExists(storeFileName string) error {
	completeStorePath := filepath.Join(config.FilesystemPathToStores, storeFileName)
	if _, err := os.Stat(completeStorePath); os.IsNotExist(err) {
		err := ensureFileSystemStoreExists(completeStorePath)
		if err != nil {
			return err
		}
	}

	return nil
}

func ensureFileSystemStoreExists(pathToStore string) error {
	err := ensureDirExists(pathToStore)
	if err != nil {
		return err
	}

	emptyArray := []byte("[]")
	err = os.WriteFile(pathToStore, emptyArray, 0600)
	if err != nil {
		return err
	}

	return nil
}

func ensureDirExists(fileName string) error {
	dirName := filepath.Dir(fileName)
	if _, serr := os.Stat(dirName); serr != nil {
		merr := os.MkdirAll(dirName, os.ModePerm)
		if merr != nil {
			return merr
		}
	}

	return nil
}

// GetCompletePathToFileStore gets the complete path to a file store.
func GetCompletePathToFileStore(storeName string) string {
	return filepath.Join(config.FilesystemPathToStores, storeName)
}

// TransformObjectToLoadedObject transform an object into an loadedObject.
func TransformObjectToLoadedObject[T, R any](object T) (R, error) {
	var loadedObject R

	serializedData, err := json.Marshal(object)
	if err != nil {
		return loadedObject, err
	}

	err = json.Unmarshal(serializedData, &loadedObject)
	if err != nil {
		return loadedObject, err
	}

	return loadedObject, err
}

// GetStoreFilenameForUUID returns the full filename for a given pndUUID and suffix.
func GetStoreFilenameForUUID(pndUUID uuid.UUID, deviceFilenameSuffix string) string {
	return pndUUID.String() + "-" + deviceFilenameSuffix
}
