package cmds

import (
	"agent/commons/adata"
	"agent/commons/debug"
	"agent/commons/utils"
	"agent/defines/dcmds"
	"agent/defines/derrs"
	"agent/defines/devent/daction"
	"agent/defines/devent/dcategory"
	"context"
	"fmt"
	"path/filepath"
	"runtime"
	"strings"
)

type FileCreateCmd struct {
	dcmds.UserToAgentCmd
}

func (c *FileCreateCmd) Category() []Category {
	return []Category{dcategory.Agent, dcategory.Rfs, dcategory.File}
}

func (c *FileCreateCmd) Action() Action {
	return daction.Create
}

func (c *FileCreateCmd) Execute(ctx context.Context, eventIn IEvent) (eventOut IEvent, err error) {
	debug.Log("FileCreateCmd")

	meta := eventIn.Meta()

	path, ok := meta["path"].(string)
	if !ok {
		return nil, derrs.NewIncorrectParamsError("path not found")
	}
	rewrite, _ := meta["rewrite"].(bool)

	if strings.HasSuffix(path, "/") || strings.HasSuffix(path, "\\") {
		return nil, derrs.NewIncorrectParamsError("path is a directory")
	}

	if runtime.GOOS == "windows" {
		fileName := filepath.Base(path)
		if strings.ContainsAny(fileName, `<>:"/\|?*`) {
			return nil, derrs.NewIncorrectParamsError("invalid characters in file name")
		}
	}

	path = normalizePath(path)
	dir := filepath.Dir(path)

	if utils.FileIsExist(path) {
		if !rewrite {
			return nil, derrs.NewIncorrectParamsError("file already exists and rewrite is false")
		}
		// Подбираем имя для копии
		extension := utils.FileExtension(path)
		name := utils.FileName(path)
		for i := 1; ; i++ {
			copyName := fmt.Sprintf("%s (%d)%s", name, i, extension)
			if utils.FileIsExist(filepath.Join(dir, copyName)) {
				continue
			}
			path = filepath.Join(dir, copyName)
			break
		}
	}

	if err = utils.DirCreate(dir); err != nil {
		return nil, err
	}

	defer func() {
		if err == nil {
			eventOut, err = listFoldersToResultEvent(eventIn, dir)
		}
	}()

	dataSize := eventIn.DataSize()
	defer func() {
		if err != nil {
			debug.Logf("FileCreateError(%s): %s\n", path, err)
			return
		}
		debug.Logf("File: %s, Size: %d\n\n", path, dataSize)
		eventOut, err = listFoldersToResultEvent(eventIn, dir)
	}()

	if dataSize == 0 {
		// Создается пустой файл
		if err = utils.FileCreate(path, nil); err != nil {
			return nil, err
		}
		return nil, nil
	}

	if data := eventIn.Data(); data != nil {
		if size, err := data.Size(); err != nil {
			return nil, err
		} else if size != dataSize {
			return nil, derrs.NewIncorrectParamsError("data size mismatch")
		} else if size == 0 {
			return nil, nil
		}

		// Если данные представлены в виде файла, открываем его, иначе при чтении возникнет ошибка
		if fileData, ok := data.(adata.IDataFromFile); ok {
			if err := fileData.Open(); err != nil {
				return nil, err
			}
			defer fileData.Close()
		}

		if _, err := utils.FileCreateFromReader(path, data); err != nil {
			return nil, err
		}
	}

	return nil, nil
}
