/*
 * Copyright 2026 Oleg Borodin <onborodin@gmail.com>
 */
package test

import (
	"bytes"
	"context"
	"fmt"
	"sync"
	"testing"
	"time"

	"mstore/app/server"
	"mstore/pkg/filecli"

	"github.com/stretchr/testify/require"
)

func TestFileLife(t *testing.T) {
	var srvport int64 = 10250
	srvdir := t.TempDir()
	srvaddr := fmt.Sprintf("127.0.0.1:%d", srvport)

	srv, err := server.NewServer()
	require.NoError(t, err)
	{
		err = srv.Configure()
		require.NoError(t, err)

		useTmpDir := true
		if useTmpDir {
			srv.SetDatadir(srvdir)
			srv.SetLogdir(srvdir)
			srv.SetRundir(srvdir)
		}
		srv.SetPort(srvport)

		err = srv.Build()
		require.NoError(t, err)

		var svcWG sync.WaitGroup
		errPipe := make(chan error, 5)

		startFunc := func() {
			err := srv.Service().Run()
			errPipe <- err
			svcWG.Done()
		}

		stopFunc := func() {
			srv.Service().Stop()
			svcWG.Wait()
			err = <-errPipe
			require.NoError(t, err)
		}
		defer stopFunc()

		svcWG.Add(1)
		go startFunc()
		time.Sleep(1 * time.Second)
	}

	fileaddr := srvaddr + "/foo2/bare.bin"
	filedata := []byte("Hello, World")
	filesize := int64(len(filedata))
	user, pass := "mstore", "mstore"
	diraddr := srvaddr + "/foo"
	{
		// PutFile
		file := bytes.NewReader(filedata)
		size := int64(len(filedata))
		fmt.Printf("=== PutFile ===\n")
		timeout := 10 * time.Second
		ctx, _ := context.WithTimeout(context.Background(), timeout)
		ref, err := filecli.ParsePath(fileaddr)
		require.NoError(t, err)
		fmt.Printf("Raw: %s\n", ref.Raw())
		ref.SetUserinfo(user, pass)

		mw := filecli.NewBasicAuthMiddleware(ref.Userinfo())
		cli := filecli.NewClient(nil, mw)
		err = cli.PutFile(ctx, ref.Raw(), file, size)
		require.NoError(t, err)
	}
	{
		// GetFile
		file := bytes.NewBuffer(nil)
		fmt.Printf("=== GetFile ===\n")
		timeout := 10 * time.Second
		ctx, _ := context.WithTimeout(context.Background(), timeout)
		ref, err := filecli.ParsePath(fileaddr)
		require.NoError(t, err)
		fmt.Printf("Raw: %s\n", ref.Raw())
		ref.SetUserinfo(user, pass)

		mw := filecli.NewBasicAuthMiddleware(ref.Userinfo())
		cli := filecli.NewClient(nil, mw)
		exist, err := cli.GetFile(ctx, ref.Raw(), file)
		require.NoError(t, err)
		require.True(t, exist)
	}
	{
		// FileInfo
		fmt.Printf("=== FileInfo ===\n")
		timeout := 10 * time.Second
		ctx, _ := context.WithTimeout(context.Background(), timeout)
		ref, err := filecli.ParsePath(fileaddr)
		require.NoError(t, err)
		fmt.Printf("Raw: %s\n", ref.Raw())
		ref.SetUserinfo(user, pass)

		mw := filecli.NewBasicAuthMiddleware(ref.Userinfo())
		cli := filecli.NewClient(nil, mw)
		exist, size, digest, err := cli.FileInfo(ctx, ref.Raw())
		require.NoError(t, err)
		require.True(t, exist)
		require.Equal(t, size, filesize)
		fmt.Printf("Digest: %s\n", digest)
	}
	{
		// FileList
		fmt.Printf("=== FileList ===\n")
		timeout := 10 * time.Second
		ctx, _ := context.WithTimeout(context.Background(), timeout)
		ref, err := filecli.ParsePath(diraddr)
		require.NoError(t, err)
		ref.SetUserinfo(user, pass)
		ref.PathType(filecli.PathTypePrefix)
		fmt.Printf("Raw: %s\n", ref.Raw())

		mw := filecli.NewBasicAuthMiddleware(ref.Userinfo())
		cli := filecli.NewClient(nil, mw)
		list, err := cli.ListFiles(ctx, ref.Raw())
		require.NoError(t, err)
		fmt.Printf("List: %s\n", list)
	}
	{
		// DeleteFile
		fmt.Printf("=== FileList ===\n")
		timeout := 10 * time.Second
		ctx, _ := context.WithTimeout(context.Background(), timeout)
		ref, err := filecli.ParsePath(fileaddr)
		require.NoError(t, err)
		ref.SetUserinfo(user, pass)
		//ref.PathType(filecli.PathTypePrefix)
		fmt.Printf("Raw: %s\n", ref.Raw())

		mw := filecli.NewBasicAuthMiddleware(ref.Userinfo())
		cli := filecli.NewClient(nil, mw)
		exist, err := cli.DeleteFile(ctx, ref.Raw())
		require.NoError(t, err)
		fmt.Printf("Exist: %v\n", exist)
		require.True(t, exist)
	}
	{
		// DeleteFile
		fmt.Printf("=== FileList ===\n")
		timeout := 10 * time.Second
		ctx, _ := context.WithTimeout(context.Background(), timeout)
		ref, err := filecli.ParsePath(fileaddr)
		require.NoError(t, err)
		ref.SetUserinfo(user, pass)
		//ref.PathType(filecli.PathTypePrefix)
		fmt.Printf("Raw: %s\n", ref.Raw())

		mw := filecli.NewBasicAuthMiddleware(ref.Userinfo())
		cli := filecli.NewClient(nil, mw)
		exist, err := cli.DeleteFile(ctx, ref.Raw())
		require.NoError(t, err)
		fmt.Printf("Exist: %v\n", exist)
		require.False(t, exist)
	}
}
