package archive

import (
	"context"
	"io/fs"
	"strings"
	"time"

	"git.kmsign.ru/royalcat/tstor/server/src/vfs"
)

type archiveLoader func(ctx context.Context, archivePath string, r vfs.File, size int64) (map[string]fileEntry, error)

var _ vfs.Filesystem = &ArchiveFS{}

type fileEntry struct {
	fs.FileInfo
	open func(ctx context.Context) (vfs.File, error)
}

type ArchiveFS struct {
	name  string
	size  int64
	files map[string]fileEntry

	modTime time.Time
}

// Rename implements Filesystem.
func (a *ArchiveFS) Rename(ctx context.Context, oldpath string, newpath string) error {
	return vfs.ErrNotImplemented
}

// ModTime implements Filesystem.
func (a *ArchiveFS) ModTime() time.Time {
	return a.modTime
}

// Mode implements Filesystem.
func (a *ArchiveFS) Mode() fs.FileMode {
	return fs.ModeDir
}

// Size implements Filesystem.
func (a *ArchiveFS) Size() int64 {
	return int64(a.size)
}

// Sys implements Filesystem.
func (a *ArchiveFS) Sys() any {
	return nil
}

// FsName implements Filesystem.
func (a *ArchiveFS) FsName() string {
	return "archivefs"
}

func (d *Daemon) NewArchiveFS(ctx context.Context, archivePath, name string, f vfs.File, size int64, loader archiveLoader) (*ArchiveFS, error) {
	archiveFiles, err := loader(ctx, archivePath, f, size)
	if err != nil {
		return nil, err
	}

	// TODO make optional
	singleDir := true
	for k := range archiveFiles {
		if !strings.HasPrefix(k, "/"+name+"/") {
			singleDir = false
			break
		}
	}

	files := make(map[string]fileEntry, len(archiveFiles))
	for k, v := range archiveFiles {
		// TODO make optional
		if strings.Contains(k, "/__MACOSX/") {
			continue
		}

		if singleDir {
			k, _ = strings.CutPrefix(k, "/"+name)
		}

		files[k] = v
	}

	// FIXME configurable
	files["/.forcegallery"] = fileEntry{
		FileInfo: vfs.NewFileInfo("/.forcegallery", 0, time.Time{}),
		open: func(ctx context.Context) (vfs.File, error) {
			return vfs.NewMemoryFile(".forcegallery", []byte{}), nil
		},
	}

	return &ArchiveFS{
		name:  name,
		size:  size,
		files: files,
	}, nil
}