package filetype

import (
	"bytes"
	"io"
	"mime"
	"strings"

	"github.com/cozy/cozy-stack/pkg/consts"
	ftype "github.com/h2non/filetype"
)

// DefaultType is the type used when we can't know/guess the filetype.
const DefaultType = "application/octet-stream"

// ByExtension calls mime.TypeByExtension, and removes optional parameters, to
// keep only the type and subtype.
// Example: text/html
func ByExtension(ext string) string {
	switch ext {
	case ".cozy-note":
		return consts.NoteMimeType
	case ".url":
		return consts.ShortcutMimeType
	}
	mimeParts := strings.SplitN(mime.TypeByExtension(ext), ";", 2)
	return strings.TrimSpace(mimeParts[0])
}

// Match returns the mime-type (no charset) if it can guess from the first
// bytes, or the default content-type else.
func Match(buf []byte) string {
	mimetype := DefaultType
	if kind, err := ftype.Match(buf); err == nil {
		mimetype = kind.MIME.Value
	}
	return mimetype
}

// FromReader takes a reader, sniffs the beginning of it, and returns the
// mime-type (no charset) and a new reader that's the concatenation of the
// bytes sniffed and the remaining reader.
func FromReader(r io.Reader) (string, io.Reader) {
	var buf bytes.Buffer
	_, err := io.Copy(&buf, io.LimitReader(r, 512))
	if err != nil {
		return DefaultType, io.MultiReader(&buf, errReader{err})
	}
	return Match(buf.Bytes()), io.MultiReader(&buf, r)
}

// errReader is an io.Reader which just returns err.
type errReader struct{ err error }

func (er errReader) Read([]byte) (int, error) { return 0, er.err }
