/*
 * Copyright 2026 Oleg Borodin <onborodin@gmail.com>
 *
 * This work is published and licensed under a Creative Commons
 * Attribution-NonCommercial-NoDerivatives 4.0 International License.
 *
 * Distribution of this work is permitted, but commercial use and
 * modifications are strictly prohibited.
 */
package test

import (
	"context"
	"fmt"
	"math/rand"
	"os"
	"path/filepath"
	"sync"
	"testing"
	"time"

	"mstore/app/server"
	"mstore/pkg/client"
	"mstore/pkg/terms"

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

func TestFileLife(t *testing.T) {
	var srvport int64 = 10250
	srvdir := t.TempDir()
	srvaddr := fmt.Sprintf("mstore:mstore@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)
	}
	{
		// ServiceHello
		fmt.Printf("=== ServiceHello ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		helloRes, err := cli.ServiceHello(ctx, srvaddr+"/hello", 1*time.Second)
		require.NoError(t, err)
		require.True(t, helloRes)
	}

	filesize := 32
	{
		// PutFile
		tmpdir := t.TempDir()
		tmpfile := filepath.Join(tmpdir, "foo.bin")

		filedata := make([]byte, filesize)
		_, err = rand.Read(filedata)
		require.NoError(t, err)

		err := os.WriteFile(tmpfile, filedata, 0666)
		require.NoError(t, err)

		fmt.Printf("=== PutFile ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		err = cli.PutFile(ctx, tmpfile, srvaddr+"/foo.bin")
		require.NoError(t, err)
	}
	{
		// FileInfo
		fmt.Printf("=== FileInfo ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		exists, file, err := cli.FileInfo(ctx, srvaddr+"/foo.bin")
		require.NoError(t, err)
		require.True(t, exists)
		require.NotNil(t, file)
	}
	{
		// GetFile
		fmt.Printf("=== GetFile ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		tmpdir := t.TempDir()
		tmpfile := filepath.Join(tmpdir, "foo.bin")

		recsize, err := cli.GetFile(ctx, srvaddr+"/foo.bin", tmpfile)
		require.NoError(t, err)
		require.Equal(t, int64(filesize), recsize)
	}
	{
		// ListFiles
		fmt.Printf("=== ListFiles ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		files, err := cli.ListFiles(ctx, srvaddr+"/", terms.AsFinePath)
		require.NoError(t, err)
		require.NotZero(t, len(files))
	}
	{
		// DeleteFile
		fmt.Printf("=== DeleteFile ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		err = cli.DeleteFile(ctx, srvaddr+"/foo.bin")
		require.NoError(t, err)
	}
	{
		// !FileInfo
		fmt.Printf("=== FileInfo ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		exists, _, err := cli.FileInfo(ctx, srvaddr+"/foo.bin")
		require.NoError(t, err)
		require.False(t, exists)

	}

}
