package cmds

import (
	"agent/commons/utils"
	"io/fs"
	"os"
	"strconv"
	"strings"
	"syscall"
	"unicode/utf16"

	"golang.org/x/sys/windows"
)

func listDrives() (res []string, err error) {
	// FIX_ME: может использовать gopsutil для получения списка дисков? Иначе надо писать свои версии для Linux/MacOS
	buffSize, err := windows.GetLogicalDriveStrings(0, nil)
	if err != nil {
		return nil, err
	}
	buff := make([]uint16, buffSize)
	if _, err := windows.GetLogicalDriveStrings(buffSize, &buff[0]); err != nil {
		return nil, err
	}
	tmp := utf16.Decode(buff)
	for start, end := 0, 0; end < len(tmp); end++ {
		if tmp[end] == 0 && (end-start) > 1 {
			res = append(res, string(tmp[start:end]))
			start = end + 1
		}
	}
	return res, nil
}

func listFolder(path string, deep int, full bool, expandPath bool) (res [][]string, err error) {
	var paths []string
	if path == "/" || path == "\\" {
		if paths, err = listDrives(); err != nil {
			return nil, err
		}
		res = append(res, createItemShortRaw(true, path, len(paths)))
	} else {
		paths = append(paths, path)
		if expandPath {
			items, err := listDrives()
			if err != nil {
				return nil, err
			}
			res = append(res, createItemShortRaw(true, path, len(items)))
			for _, drive := range items {
				// Пропускаем диск с которого начинается путь, он будет обработан общим алгоритмом
				if strings.HasPrefix(path, drive) {
					continue
				}
				dirInfo, err := os.Stat(drive)
				if err != nil {
					return nil, err
				}
				dirEntry := fs.FileInfoToDirEntry(dirInfo)
				item := createItem(dirEntry, drive, -1, full)
				res = append(res, item)
			}
		}
	}
	res_, err := list2(paths, deep, full, expandPath)
	if err != nil {
		return nil, err
	}
	return append(res, res_...), nil
}

func createItem(entry fs.DirEntry, path string, count int, full bool) (res []string) {
	if full {
		var size, created, updated int64
		if info, err := entry.Info(); err == nil {
			size = info.Size()
			created = int64(0)
			updated = int64(0)
			if sysInfo, ok := info.Sys().(*syscall.Win32FileAttributeData); ok {
				created = sysInfo.CreationTime.Nanoseconds()
				updated = sysInfo.LastWriteTime.Nanoseconds()
			}
		}
		return createItemFullRaw(entry.IsDir(), path, count, size, created, updated)
	}
	return createItemShortRaw(entry.IsDir(), path, count)
}

func createItemShortRaw(isDir bool, path string, count int) []string {
	item := []string{"0", path, strconv.FormatInt(int64(count), 10)}
	if isDir {
		item[0] = "1"
	}
	return item
}

func createItemFullRaw(isDir bool, path string, count int, size int64, created int64, updated int64) []string {
	item := make([]string, 0, 6)
	item = append(item, "0", path)
	item = append(item, utils.Int64ToStrList(int64(count), size, created, updated)...)
	if isDir {
		item[0] = "1"
	}
	return item
}
