/*
 * 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"
	"sync"
	"testing"
	"time"

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

	"github.com/stretchr/testify/require"

	yaml "go.yaml.in/yaml/v4"
)

func TestAccountLife(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)
		useTmp := true
		if useTmp {
			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)
	}

	username := "testuser"
	password := "testpass"

	var accountID string
	{
		// CreateAccount
		fmt.Printf("=== CreateAccount ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		accountID, err = cli.CreateAccount(ctx, srvaddr, username, password)
		require.NoError(t, err)
	}
	var grantID string
	{
		// CreateGrant
		fmt.Printf("=== CreateGrant ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		grantID, err = cli.CreateGrantByAccountID(ctx, srvaddr, accountID, terms.RightReadAccounts, ".*")
		require.NoError(t, err)
		require.Equal(t, len(grantID), 36)
	}
	{
		// UpdateGrant
		fmt.Printf("=== UpdateGrant ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		err := cli.UpdateGrant(ctx, srvaddr, grantID, ".*")
		require.NoError(t, err)
	}
	{
		// CreateGrant
		fmt.Printf("=== CreateGrant ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		grantID, err = cli.CreateGrantByAccountID(ctx, srvaddr, accountID, terms.RightWriteAccounts, ".*")
		require.NoError(t, err)
		require.Equal(t, len(grantID), 36)
		fmt.Printf("grantID: %s\n", grantID)
	}
	{
		// GetGrant
		fmt.Printf("=== GetGrant ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		grantDescr, err := cli.GetGrant(ctx, srvaddr, grantID)
		require.NoError(t, err)
		require.Equal(t, len(grantID), 36)
		fmt.Printf("grantID: %s\n", grantID)
		grantYAML, err := yaml.Marshal(grantDescr)
		require.NoError(t, err)
		fmt.Printf("account:\n%s\n", string(grantYAML))
	}
	{
		// UpdateGrant
		fmt.Printf("=== UpdateGrant ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		err := cli.UpdateGrant(ctx, srvaddr, grantID, "**")
		require.NoError(t, err)
	}
	{
		// GetGrant
		fmt.Printf("=== GetGrant ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		grantDescr, err := cli.GetGrant(ctx, srvaddr, grantID)
		require.NoError(t, err)
		require.Equal(t, len(grantID), 36)
		fmt.Printf("grantID: %s\n", grantID)
		grantYAML, err := yaml.Marshal(grantDescr)
		require.NoError(t, err)
		fmt.Printf("account:\n%s\n", string(grantYAML))
	}
	{
		// DeleteGrant
		fmt.Printf("=== DeleteGrant ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		err := cli.DeleteGrant(ctx, srvaddr, grantID)
		require.NoError(t, err)
	}
	{
		// GetAccount
		fmt.Printf("=== GetAccount ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		accountDescr, err := cli.GetAccountByID(ctx, srvaddr, accountID)
		require.NoError(t, err)
		accountYAML, err := yaml.Marshal(accountDescr)
		require.NoError(t, err)
		fmt.Printf("account:\n%s\n", string(accountYAML))
	}
	{
		// ListAccounts
		fmt.Printf("=== ListAccounts ===\n")
		cli := client.NewClient()
		ctx := context.Background()
		ctx, _ = context.WithTimeout(ctx, 1*time.Second)

		accountDescrs, err := cli.ListAccounts(ctx, srvaddr+"/")
		require.NoError(t, err)
		require.NotZero(t, len(accountDescrs))
		nameList := make([]string, 0)
		for _, item := range accountDescrs {
			nameList = append(nameList, item.Username)
		}
		accountsYAML, err := yaml.Marshal(nameList)
		fmt.Printf("accounts:\n%s\n", string(accountsYAML))

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

		err = cli.DeleteAccountByID(ctx, srvaddr, accountID)
		require.NoError(t, err)
	}

}
