package operating_system

// |@@| C

import (
	"context"
	"gardening/src/lib/spy"
	"os"
	"path/filepath"
)

type MemoryOperatingSystemSpyIpl struct {
	MemoryOperatingSystemIpl *MemoryOperatingSystemIpl
	Spy                      *spy.Spy
}

type WriteFileDataSpyRecord struct {
	Name    string
	Data    string
	Created bool
	Updated bool
}

type DeleteFileDataSpyRecord struct {
	Name    string
	Deleted bool
}

func (this *MemoryOperatingSystemSpyIpl) Kind() string {
	return this.MemoryOperatingSystemIpl.Kind()
}

func (this *MemoryOperatingSystemSpyIpl) Getwd(ctx context.Context) (string, error) {
	return this.MemoryOperatingSystemIpl.Getwd(ctx)
}

func (this *MemoryOperatingSystemSpyIpl) Getenv(ctx context.Context, key string) string {
	return this.MemoryOperatingSystemIpl.Getenv(ctx, key)
}

func (this *MemoryOperatingSystemSpyIpl) Setenv(ctx context.Context, key string, value string) error {
	return this.MemoryOperatingSystemIpl.Setenv(ctx, key, value)
}

func (this *MemoryOperatingSystemSpyIpl) LookupEnv(ctx context.Context, key string) (string, bool) {
	return this.MemoryOperatingSystemIpl.LookupEnv(ctx, key)
}

func (this *MemoryOperatingSystemSpyIpl) Remove(ctx context.Context, name string) error {
	existed := false
	if this.IsExist(ctx, name) {
		existed = true
	}

	record := &DeleteFileDataSpyRecord{
		Name: name,
	}

	err := this.MemoryOperatingSystemIpl.Remove(ctx, name)

	existing := false
	if this.IsExist(ctx, name) {
		existing = true
	}

	if err != nil && existed && !existing {
		record.Deleted = true
	}

	this.Spy.LogRecord(ctx, "remove", record)

	return err
}

func (this *MemoryOperatingSystemSpyIpl) RemoveAll(ctx context.Context, name string) error {
	return this.MemoryOperatingSystemIpl.RemoveAll(ctx, name)
}

func (this *MemoryOperatingSystemSpyIpl) WriteFile(ctx context.Context, name string, data []byte, perm os.FileMode) error {
	existed := false
	if this.IsExist(ctx, name) {
		existed = true
	}

	record := &WriteFileDataSpyRecord{
		Name: name,
		Data: string(data),
	}

	err := this.MemoryOperatingSystemIpl.WriteFile(ctx, name, data, perm)

	existing := false
	if this.IsExist(ctx, name) {
		existing = true
	}

	if err == nil && !existed && existing {
		record.Created = true
	}
	if err == nil && existed && existing {
		record.Updated = true
	}

	this.Spy.LogRecord(ctx, "write-file", record)

	return err
}

func (this *MemoryOperatingSystemSpyIpl) ReadDir(ctx context.Context, name string) ([]os.DirEntry, error) {
	return this.MemoryOperatingSystemIpl.ReadDir(ctx, name)
}

func (this *MemoryOperatingSystemSpyIpl) Stat(ctx context.Context, name string) (os.FileInfo, error) {
	return this.MemoryOperatingSystemIpl.Stat(ctx, name)
}

func (this *MemoryOperatingSystemSpyIpl) IsNotExist(ctx context.Context, err error) bool {
	return os.IsNotExist(err)
}

func (this *MemoryOperatingSystemSpyIpl) IsExist(ctx context.Context, name string) bool {
	if _, err := this.MemoryOperatingSystemIpl.Stat(ctx, name); os.IsExist(err) {
		return true
	}
	return false
}

func (this *MemoryOperatingSystemSpyIpl) ReadFile(ctx context.Context, name string) ([]byte, error) {
	this.Spy.LogRecord(ctx, "read-file", struct {
		Name string
	}{})
	return this.MemoryOperatingSystemIpl.ReadFile(ctx, name)
}

func (this *MemoryOperatingSystemSpyIpl) MkdirAll(ctx context.Context, path string, perm os.FileMode) error {
	return this.MemoryOperatingSystemIpl.MkdirAll(ctx, path, perm)
}

func (this *MemoryOperatingSystemSpyIpl) Rename(ctx context.Context, oldpath, newpath string) error {
	return this.MemoryOperatingSystemIpl.Rename(ctx, oldpath, newpath)
}

func (this *MemoryOperatingSystemSpyIpl) Walk(ctx context.Context, root string, fn filepath.WalkFunc) error {
	return this.MemoryOperatingSystemIpl.Walk(ctx, root, fn)
}

func (this *MemoryOperatingSystemSpyIpl) Chmod(ctx context.Context, name string, mode os.FileMode) error {
	return this.MemoryOperatingSystemIpl.Chmod(ctx, name, mode)
}
