package fs

import (
	"bytes"
	"io"
	"io/ioutil"
	"os"

	"gotest.tools/assert"
)

// resourcePath is an adaptor for resources so they can be used as a Path
// with PathOps.
type resourcePath struct{}

func (p *resourcePath) Path() string {
	return "manifest: not a filesystem path"
}

func (p *resourcePath) Remove() {}

type filePath struct {
	resourcePath
	file *file
}

func (p *filePath) SetContent(content io.ReadCloser) {
	p.file.content = content
}

func (p *filePath) SetUID(uid uint32) {
	p.file.uid = uid
}

func (p *filePath) SetGID(gid uint32) {
	p.file.gid = gid
}

type directoryPath struct {
	resourcePath
	directory *directory
}

func (p *directoryPath) SetUID(uid uint32) {
	p.directory.uid = uid
}

func (p *directoryPath) SetGID(gid uint32) {
	p.directory.gid = gid
}

func (p *directoryPath) AddSymlink(path, target string) error {
	p.directory.items[path] = &symlink{
		resource: newResource(defaultSymlinkMode),
		target:   target,
	}
	return nil
}

func (p *directoryPath) AddFile(path string, ops ...PathOp) error {
	newFile := &file{resource: newResource(0)}
	p.directory.items[path] = newFile
	exp := &filePath{file: newFile}
	return applyPathOps(exp, ops)
}

func (p *directoryPath) AddGlobFiles(glob string, ops ...PathOp) error {
	newFile := &file{resource: newResource(0)}
	newFilePath := &filePath{file: newFile}
	p.directory.filepathGlobs[glob] = newFilePath
	return applyPathOps(newFilePath, ops)
}

func (p *directoryPath) AddDirectory(path string, ops ...PathOp) error {
	newDir := newDirectoryWithDefaults()
	p.directory.items[path] = newDir
	exp := &directoryPath{directory: newDir}
	return applyPathOps(exp, ops)
}

// Expected returns a Manifest with a directory structured created by ops. The
// PathOp operations are applied to the manifest as expectations of the
// filesystem structure and properties.
func Expected(t assert.TestingT, ops ...PathOp) Manifest {
	if ht, ok := t.(helperT); ok {
		ht.Helper()
	}

	newDir := newDirectoryWithDefaults()
	e := &directoryPath{directory: newDir}
	assert.NilError(t, applyPathOps(e, ops))
	return Manifest{root: newDir}
}

func newDirectoryWithDefaults() *directory {
	return &directory{
		resource:      newResource(defaultRootDirMode),
		items:         make(map[string]dirEntry),
		filepathGlobs: make(map[string]*filePath),
	}
}

func newResource(mode os.FileMode) resource {
	return resource{
		mode: mode,
		uid:  currentUID(),
		gid:  currentGID(),
	}
}

func currentUID() uint32 {
	return normalizeID(os.Getuid())
}

func currentGID() uint32 {
	return normalizeID(os.Getgid())
}

func normalizeID(id int) uint32 {
	// ids will be -1 on windows
	if id < 0 {
		return 0
	}
	return uint32(id)
}

var anyFileContent = ioutil.NopCloser(bytes.NewReader(nil))

// MatchAnyFileContent is a PathOp that updates a Manifest so that the file
// at path may contain any content.
func MatchAnyFileContent(path Path) error {
	if m, ok := path.(*filePath); ok {
		m.SetContent(anyFileContent)
	}
	return nil
}

// MatchContentIgnoreCarriageReturn is a PathOp that ignores cariage return
// discrepancies.
func MatchContentIgnoreCarriageReturn(path Path) error {
	if m, ok := path.(*filePath); ok {
		m.file.ignoreCariageReturn = true
	}
	return nil
}

const anyFile = "*"

// MatchExtraFiles is a PathOp that updates a Manifest to allow a directory
// to contain unspecified files.
func MatchExtraFiles(path Path) error {
	if m, ok := path.(*directoryPath); ok {
		m.AddFile(anyFile)
	}
	return nil
}

// CompareResult is the result of comparison.
//
// See gotest.tools/assert/cmp.StringResult for a convenient implementation of
// this interface.
type CompareResult interface {
	Success() bool
	FailureMessage() string
}

// MatchFileContent is a PathOp that updates a Manifest to use the provided
// function to determine if a file's content matches the expectation.
func MatchFileContent(f func([]byte) CompareResult) PathOp {
	return func(path Path) error {
		if m, ok := path.(*filePath); ok {
			m.file.compareContentFunc = f
		}
		return nil
	}
}

// MatchFilesWithGlob is a PathOp that updates a Manifest to match files using
// glob pattern, and check them using the ops.
func MatchFilesWithGlob(glob string, ops ...PathOp) PathOp {
	return func(path Path) error {
		if m, ok := path.(*directoryPath); ok {
			m.AddGlobFiles(glob, ops...)
		}
		return nil
	}
}

// anyFileMode is represented by uint32_max
const anyFileMode os.FileMode = 4294967295

// MatchAnyFileMode is a PathOp that updates a Manifest so that the resource at path
// will match any file mode.
func MatchAnyFileMode(path Path) error {
	if m, ok := path.(manifestResource); ok {
		m.SetMode(anyFileMode)
	}
	return nil
}
