package engine

import (
	"os/user"
	"sync"
	"time"

	watcher "github.com/radovskyb/watcher"
	"github.com/rs/zerolog"

	database "github.com/deranjer/gvc/common/database"
)

type FileWatcher struct {
	*watcher.Watcher
	*zerolog.Logger
	Enabled        bool
	KeyFolder      string
	DownloadFolder string
	SyncFolder     string
	ThumbFolder    string
	DiffFolder     string
}

//Patcher contains the information needed to patch files
type Patcher struct {
	*zerolog.Logger
	KeyFolder      string
	DownloadFolder string
	SyncFolder     string
	ThumbFolder    string
	DiffFolder     string
}

type Manager struct {
	Version string //What version of the client or server are we using
	//Settings *UserSettings
	*zerolog.Logger
	*sync.WaitGroup
	//watcher              engine.FileWatcher
	patcher  Patcher
	dB       *database.DB
	Informer chan OperatingMessage
	*FilePaths
	//ProgressCommunicator io.WriteCloser
}

type CustomPlugin interface {
	Init()
	Name() string
	Description() string
}

//FilePaths holds the full paths to all the relevant folders
type FilePaths struct {
	KeyFolder      string
	DownloadFolder string
	SyncFolder     string
	ThumbFolder    string
	ObjectFolder   string
	LogFolder      string
	PluginFolder   string
}

// type PluginManager struct {
// 	engine   *qml.QQmlApplicationEngine
// 	informer chan OperatingMessage
// 	path     string
// 	plugins  []string
// }

type UserSettings struct {
	Usr           user.User
	versionFormat string
	darkMode      bool
	licenseKey    string
	override      bool
	machineID     string
	//systemSettings engine.UXSettings
}
type VersioningFormat struct {
	bigVersion    int64
	littleVersion int64
	microVersion  int64
	currentTime   time.Time
	client        string
	job           string
	userId        string
	owner         string
	hash          string
	message       string
}

// this should enumerate certain message types that the front end can retrieve
// over a channel. the manager will output certain message types at certain times.

// OpCode is a type that is used to describe what type
// of event has occurred during the management process.
type OpCode uint32

type OperatingMessage struct {
	Code        OpCode
	data        string
	CustomField string
}

func (op *OperatingMessage) Custom() string {
	if op.CustomField != "" {
		return op.CustomField
	}
	return op.data
}

// Ops
const (
	OpNewDiff OpCode = iota
	OpNewFile
	OpNewBase
	OpWatchCommencing
	OpWatchStopped
	OpMessage
	OpEnablingPlugin
	OpPluginEnabled
	OpPluginError
	OpNone
)

var ops = map[OpCode]OperatingMessage{
	OpNewDiff: {OpNewDiff, "New diff created", ""},
	OpNewFile: {OpNewFile, "New file created", ""},
	OpNewBase: {OpNewBase, "New base created", ""},
	//OpWatchCommencing: {Op_WatchCommencing, "File watching has started", ""},
	//OpWatchStopped:    {Op_WatchStopped, "File watching has stopped", ""},
	OpMessage:        {OpMessage, "Custom message attached - ", ""},
	OpEnablingPlugin: {OpEnablingPlugin, "Enabling Plugin - ", ""},
	OpPluginEnabled:  {OpPluginEnabled, "Plugin Enabled", ""},
	OpPluginError:    {OpPluginError, "Error enabling plugin", ""},
	OpNone:           {OpNone, "No error code known", ""},
}

// String prints the string version of the Op consts
func (e OpCode) String() string {
	if op, found := ops[e]; found {
		return op.data
	}
	return "???"
}

func (e OpCode) Retrieve() OperatingMessage {
	if op, found := ops[e]; found {
		return op
	}
	return ops[OpNone]
}
