package vfs_test

import (
	"archive/zip"
	"bytes"
	"context"
	"testing"

	"git.kmsign.ru/royalcat/tstor/src/vfs"
	"github.com/stretchr/testify/require"
)

func createZip(files map[string][]byte) ([]byte, error) {
	buf := bytes.NewBuffer(nil)
	zw := zip.NewWriter(buf)

	for name, data := range files {
		fw, err := zw.Create(name)
		if err != nil {
			return nil, err
		}

		_, err = fw.Write(data)
		if err != nil {
			return nil, err
		}
	}
	err := zw.Flush()
	if err != nil {
		return nil, err
	}

	err = zw.Close()
	if err != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

func TestResolverFs(t *testing.T) {
	t.Parallel()
	ctx := context.Background()

	testZip, err := createZip(map[string][]byte{
		"123.txt":       []byte("123"),
		"files/321.txt": []byte("321"),
	})
	require.NoError(t, err)

	fs := vfs.NewResolveFS(vfs.NewMemoryFS("/", map[string]*vfs.MemoryFile{
		"/data/123.zip": vfs.NewMemoryFile("123.zip", testZip),
	}), vfs.ArchiveFactories)

	t.Run("dir", func(t *testing.T) {
		t.Parallel()
		require := require.New(t)

		dirs := []string{
			"/data", "/", "/.",
			"/data/123.zip", "/data/123.zip/files", "/data/123.zip/files/.",
		}

		for _, dir := range dirs {
			file, err := fs.Open(ctx, dir)
			require.NoError(err)
			require.True(file.IsDir())

			stat, err := file.Info()
			require.NoError(err)
			require.True(stat.IsDir())
		}

		entries, err := fs.ReadDir(ctx, "/data")
		require.NoError(err)
		require.Len(entries, 1)

		for _, e := range entries {
			switch e.Name() {
			case "123.zip":
				require.True(e.IsDir())
				require.IsType(&vfs.ArchiveFS{}, e)
			}
		}

		entries, err = fs.ReadDir(ctx, "/data/123.zip/files")
		require.NoError(err)
		require.Len(entries, 1)

		entries, err = fs.ReadDir(ctx, "/data/123.zip")
		require.NoError(err)
		require.Len(entries, 3)

		for _, e := range entries {
			switch e.Name() {
			case "files":
				require.True(e.IsDir())
			case "123.txt":
				require.False(e.IsDir())
			}
		}
	})
}

// func TestResolver(t *testing.T) {
// 	t.Parallel()
// 	resolver := newResolver(ArchiveFactories)
// 	ctx := context.Background()

// 	t.Run("nested fs", func(t *testing.T) {
// 		t.Parallel()
// 		require := require.New(t)

// 		fsPath, nestedFs, nestedFsPath, err := resolver.resolvePath(ctx, "/f1.rar/f2.rar", func(_ context.Context, path string) (File, error) {
// 			require.Equal("/f1.rar", path)
// 			return &vfs.Dummy{}, nil
// 		})
// 		require.NoError(err)
// 		require.Equal("/f1.rar", fsPath)
// 		require.Equal("/f2.rar", nestedFsPath)
// 		require.IsType(&vfs.ArchiveFS{}, nestedFs)
// 	})
// 	t.Run("root", func(t *testing.T) {
// 		t.Parallel()
// 		require := require.New(t)

// 		fsPath, nestedFs, nestedFsPath, err := resolver.resolvePath(ctx, "/", func(_ context.Context, path string) (File, error) {
// 			require.Equal("/", path)
// 			return &Dummy{}, nil
// 		})
// 		require.NoError(err)
// 		require.Nil(nestedFs)
// 		require.Equal("/", fsPath)
// 		require.Equal("", nestedFsPath)
// 	})

// 	t.Run("root dirty", func(t *testing.T) {
// 		t.Parallel()
// 		require := require.New(t)

// 		fsPath, nestedFs, nestedFsPath, err := resolver.resolvePath(ctx, "//.//", func(_ context.Context, path string) (File, error) {
// 			require.Equal("/", path)
// 			return &Dummy{}, nil
// 		})
// 		require.NoError(err)
// 		require.Nil(nestedFs)
// 		require.Equal("/", fsPath)
// 		require.Equal("", nestedFsPath)
// 	})

// 	t.Run("root dirty 2", func(t *testing.T) {
// 		t.Parallel()
// 		require := require.New(t)

// 		fsPath, nestedFs, nestedFsPath, err := resolver.resolvePath(ctx, "/.", func(_ context.Context, path string) (File, error) {
// 			require.Equal("/", path)
// 			return &Dummy{}, nil
// 		})
// 		require.NoError(err)
// 		require.Nil(nestedFs)
// 		require.Equal("/", fsPath)
// 		require.Equal("", nestedFsPath)
// 	})

// 	t.Run("fs dirty", func(t *testing.T) {
// 		t.Parallel()
// 		require := require.New(t)

// 		fsPath, nestedFs, nestedFsPath, err := resolver.resolvePath(ctx, "//.//f1.rar", func(_ context.Context, path string) (File, error) {
// 			require.Equal("/f1.rar", path)
// 			return &Dummy{}, nil
// 		})
// 		require.NoError(err)
// 		require.Equal("/f1.rar", fsPath)
// 		require.Equal("/", nestedFsPath)
// 		require.IsType(&ArchiveFS{}, nestedFs)
// 	})
// 	t.Run("inside folder", func(t *testing.T) {
// 		t.Parallel()
// 		require := require.New(t)

// 		fsPath, nestedFs, nestedFsPath, err := resolver.resolvePath(ctx, "//test1/f1.rar", func(_ context.Context, path string) (File, error) {
// 			require.Equal("/test1/f1.rar", path)
// 			return &Dummy{}, nil
// 		})
// 		require.NoError(err)
// 		require.IsType(&ArchiveFS{}, nestedFs)
// 		require.Equal("/test1/f1.rar", fsPath)
// 		require.Equal("/", nestedFsPath)
// 	})
// }

// func TestFiles(t *testing.T) {
// 	t.Parallel()
// 	require := require.New(t)

// 	files := map[string]*vfs.DummyFile{
// 		"/test/file.txt":  &vfs.DummyFile{},
// 		"/test/file2.txt": &vfs.DummyFile{},
// 		"/test1/file.txt": &vfs.DummyFile{},
// 	}
// 	{
// 		file, err := getFile(files, "/test")
// 		require.NoError(err)
// 		require.Equal(&dir{name: "test"}, file)
// 	}
// 	{
// 		file, err := getFile(files, "/test/file.txt")
// 		require.NoError(err)
// 		require.Equal(&Dummy{}, file)
// 	}
// 	{
// 		out, err := listDirFromFiles(files, "/test")
// 		require.NoError(err)
// 		require.Len(out, 2)
// 		require.Equal("file.txt", out[0].Name())
// 		require.Equal("file2.txt", out[1].Name())
// 		require.False(out[0].IsDir())
// 		require.False(out[1].IsDir())
// 	}
// 	{
// 		out, err := listDirFromFiles(files, "/test1")
// 		require.NoError(err)
// 		require.Len(out, 1)
// 		require.Equal("file.txt", out[0].Name())
// 		require.False(out[0].IsDir())
// 	}
// 	{
// 		out, err := listDirFromFiles(files, "/")
// 		require.NoError(err)
// 		require.Len(out, 2)
// 		require.Equal("test", out[0].Name())
// 		require.Equal("test1", out[1].Name())
// 		require.True(out[0].IsDir())
// 		require.True(out[1].IsDir())
// 	}
// }