package utils

import (
	"fmt"
	"io"
	"net/url"
	"os"
	"path/filepath"
	"strings"

	"golang.org/x/xerrors"

	"github.com/aquasecurity/trivy-db/pkg/types"
)

var (
	cacheDir string
)

// DefaultCacheDir returns/creates the cache-dir to be used for baseline operations
func DefaultCacheDir() string {
	tmpDir, err := os.UserCacheDir()
	if err != nil {
		tmpDir = os.TempDir()
	}
	return filepath.Join(tmpDir, "baseline")
}

func TrivyCacheDir(cache_dir string) string {
	return filepath.Join(cache_dir, "trivy")
}

// CacheDir returns the directory used for caching
func CacheDir() string {
	return cacheDir
}

// SetCacheDir sets the baseline cacheDir
func SetCacheDir(dir string) {
	cacheDir = dir
}

func DefaultTrivySeverity() string {
	return strings.Join(types.SeverityNames, ",")
}

// CopyFile copies the file content from scr to dst
func CopyFile(src, dst string) (int64, error) {
	sourceFileStat, err := os.Stat(src)
	if err != nil {
		return 0, xerrors.Errorf("file (%s) stat error: %w", src, err)
	}

	if !sourceFileStat.Mode().IsRegular() {
		return 0, fmt.Errorf("%s is not a regular file", src)
	}

	source, err := os.Open(src)
	if err != nil {
		return 0, err
	}
	defer source.Close()

	destination, err := os.Create(dst)
	if err != nil {
		return 0, err
	}
	defer destination.Close()
	n, err := io.Copy(destination, source)
	return n, err
}

func ParseImageUrl(target string) (map[string]string, error) {
	t := strings.Split(target, ":")
	if len(t) == 2 {
		_, err := url.Parse(t[0])
		if err != nil {
			return nil, err
		} else {
			info := make(map[string]string)
			info["url"] = target
			info["name"] = filepath.Base(t[0])
			info["version"] = t[1]
			return info, nil
		}
	} else {
		return nil, xerrors.Errorf("Invalid image url `%s`", target)
	}
}

func ParseRepoUrl(target string) (map[string]string, *url.URL, error) {
	t, err := url.Parse(target)
	if err != nil {
		if strings.HasPrefix(target, "git@") {
			return nil, nil, xerrors.Errorf("Invalid repo url `%s`, git protocol is not supported", target)
		} else {
			return nil, nil, xerrors.Errorf("Failed to parse repo url `%s`, %+v", target, err)
		}
	}

	if t.Scheme != "https" {
		t.Scheme = "https"
	}

	if strings.HasSuffix(t.Path, ".git") {
		t.Path = strings.TrimSuffix(t.Path, ".git")
	}

	url, err := url.Parse(t.String())
	if err != nil {
		return nil, nil, xerrors.Errorf("Failed to parse repo url `%s`, %+v", target, err)
	} else {
		ref := strings.Split(url.Fragment, "@")
		if len(ref) == 2 {
			info := make(map[string]string)
			info["url"] = t.String()
			info["name"] = url.Path
			info["version"] = ref[1]
			return info, url, nil
		} else {
			return nil, nil, xerrors.Errorf("Invalid reference in repo url `%s`", target)
		}
	}
}
