// Copyright (C) 2022 Marius Schellenberger

package parse

import (
	"cachefs/pkg/provider"
	"cachefs/pkg/provider/crypto"
	"cachefs/pkg/provider/filter"
	"cachefs/pkg/provider/os"
	"cachefs/pkg/provider/sftp"
	"errors"
	"fmt"
	neturl "net/url"
	"path/filepath"
	"regexp"

	"k8s.io/klog/v2/klogr"
)

var (
	ErrPathNotAbsolute   = errors.New("path is not absolute")
	ErrUnsupportedScheme = errors.New("unsupported scheme")
)

func TryParse(url string) error {
	u, err := neturl.Parse(url)
	if err != nil {
		return err
	}
	if !filepath.IsAbs(u.Path) {
		return ErrPathNotAbsolute
	}
	switch u.Scheme {
	case "file", "sftp":
	default:
		return fmt.Errorf("%w: %s", ErrUnsupportedScheme, u.Scheme)
	}
	return nil
}

func Paths(url string) (paths []string) {
	u, err := neturl.Parse(url)
	if err != nil {
		return
	}
	switch u.Scheme {
	case "file":
		paths = append(paths, u.Path)
	case "sftp":
		q, err := neturl.ParseQuery(u.RawQuery)
		if err != nil {
			return
		}
		known, err := sftp.KnownHosts(q)
		if err != nil {
			return
		}
		paths = append(paths, known)
		if key := q.Get(sftp.KeyParam); key != "" {
			paths = append(paths, key)
		}
	}
	return
}

func FS(url string, key []byte, re *regexp.Regexp, block bool) (provider.FS, error) {
	u, err := neturl.Parse(url)
	if err != nil {
		return nil, err
	}
	if !filepath.IsAbs(u.Path) {
		return nil, ErrPathNotAbsolute
	}
	var fs provider.FS
	switch u.Scheme {
	case "file":
		fs, err = os.NewFS(u.Path)
	case "sftp":
		fs, err = sftp.NewFS(u, block, klogr.New().WithName("sftp"))
	default:
		return nil, fmt.Errorf("%w: %s", ErrUnsupportedScheme, u.Scheme)
	}
	if err != nil {
		return nil, err
	}
	if key != nil {
		fs, err = crypto.NewFS(fs, key)
		if err != nil {
			return nil, err
		}
	}
	if re != nil {
		fs, err = filter.NewFS(fs, re)
	}
	return fs, err
}
