/*
 * 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 (
	"github.com/stretchr/testify/require"

	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"math/rand"
	"net/http"
	"net/http/httptest"
	"testing"

	"mstore/app/handler"
	"mstore/app/operator"
	"mstore/app/router"
	"mstore/app/server"
	"mstore/pkg/auxhttp"
)

func TestAccountOperations(t *testing.T) {
	var err error
	fmt.Printf("=== MakeServer ===\n")
	srv, err := server.NewServer()
	require.NoError(t, err)

	var srvport int64 = 10240 + rand.Int63n(1024)
	srvdir := t.TempDir()
	//srvaddr := fmt.Sprintf("127.0.0.1:%d", srvport)

	{
		err = srv.Configure()
		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)
	}
	username := "testuser"
	password := "testpass"
	{
		fmt.Printf("=== ServiceHello ===\n")
		reqPath := "/service/hello"
		routePath := "/service/hello"

		rout := router.NewRouter()
		hand := srv.Handler()
		rout.Get(routePath, hand.SendHello)

		request, err := http.NewRequest("GET", reqPath, nil)
		require.NoError(t, err)

		basic := auxhttp.EncodeBasicAuth(username, password)
		request.Header.Add("Authorization", basic)

		recorder := httptest.NewRecorder()
		rout.ServeHTTP(recorder, request)
		require.Equal(t, http.StatusOK, recorder.Code)

		fmt.Printf("Response code: %d\n", recorder.Code)

		bodyReader := recorder.Body
		bodyBytes, err := io.ReadAll(bodyReader)

		fmt.Printf("Response body: %s\n", string(bodyBytes))
	}

	return

	var accountID string
	var accountName = "testname1"
	{
		fmt.Printf("=== CreateAccount ===\n")
		reqpath := `/v3/api/account/create`
		routepath := `/v3/api/account/create`

		rout := router.NewRouter()
		hand := srv.Handler()
		require.NotNil(t, hand)

		req := operator.CreateAccountParams{
			Username: accountName,
			Password: "testpass",
		}
		reqdata, err := json.Marshal(req)
		require.NoError(t, err)

		reqsize := len(reqdata)
		reqsrc := bytes.NewReader(reqdata)

		request, err := http.NewRequest("POST", reqpath, reqsrc)
		require.NoError(t, err)

		request.ContentLength = int64(reqsize)
		request.Header.Set("Content-Type", "application/json")

		recorder := httptest.NewRecorder()

		rout.Post(routepath, hand.CreateAccount)
		rout.ServeHTTP(recorder, request)

		fmt.Printf("Response code: %d\n", recorder.Code)

		bodyReader := recorder.Body
		bodyBytes, err := io.ReadAll(bodyReader)

		fmt.Printf("Response body: %s\n", string(bodyBytes))
		require.Equal(t, http.StatusOK, recorder.Code)

		jsonBuffer := bytes.NewBuffer(nil)
		err = json.Indent(jsonBuffer, bodyBytes, "", "    ")
		require.NoError(t, err)
		fmt.Printf("Formatted body: \n%s\n", jsonBuffer.String())

		resp := handler.Response[operator.CreateAccountResult]{}
		err = json.Unmarshal(bodyBytes, &resp)
		require.False(t, resp.Error)
		require.Equal(t, len(resp.Result.AccountID), 36)
		accountID = resp.Result.AccountID
	}
	fmt.Printf("AccountID: %s\n", accountID)
	{
		fmt.Printf("=== UpdateAccount ===\n")
		reqpath := `/v3/api/account/create`
		routepath := `/v3/api/account/create`

		rout := router.NewRouter()
		hand := srv.Handler()
		require.NotNil(t, hand)

		req := operator.UpdateAccountParams{
			AccountID:   accountID,
			NewPassword: "newpass",
		}
		reqdata, err := json.Marshal(req)
		require.NoError(t, err)

		reqsize := len(reqdata)
		reqsrc := bytes.NewReader(reqdata)

		request, err := http.NewRequest("POST", reqpath, reqsrc)
		require.NoError(t, err)

		request.ContentLength = int64(reqsize)
		request.Header.Set("Content-Type", "application/json")

		recorder := httptest.NewRecorder()

		rout.Post(routepath, hand.UpdateAccount)
		rout.ServeHTTP(recorder, request)

		fmt.Printf("Response code: %d\n", recorder.Code)

		bodyReader := recorder.Body
		bodyBytes, err := io.ReadAll(bodyReader)

		fmt.Printf("Response body: %s\n", string(bodyBytes))
		require.Equal(t, http.StatusOK, recorder.Code)

		jsonBuffer := bytes.NewBuffer(nil)
		err = json.Indent(jsonBuffer, bodyBytes, "", "    ")
		require.NoError(t, err)
		fmt.Printf("Formatted body: \n%s\n", jsonBuffer.String())

		resp := handler.Response[operator.UpdateAccountResult]{}
		err = json.Unmarshal(bodyBytes, &resp)
		require.False(t, resp.Error)
	}

	{
		fmt.Printf("=== GetAccount ===\n")
		reqpath := `/v3/api/account/get`
		routepath := `/v3/api/account/get`

		rout := router.NewRouter()
		hand := srv.Handler()
		require.NotNil(t, hand)

		req := operator.GetAccountParams{
			AccountID: accountID,
		}
		reqdata, err := json.Marshal(req)
		require.NoError(t, err)

		reqsize := len(reqdata)
		reqsrc := bytes.NewReader(reqdata)

		request, err := http.NewRequest("POST", reqpath, reqsrc)
		require.NoError(t, err)

		request.ContentLength = int64(reqsize)
		request.Header.Set("Content-Type", "application/json")

		recorder := httptest.NewRecorder()
		rout.Post(routepath, hand.GetAccount)

		rout.ServeHTTP(recorder, request)

		fmt.Printf("Response code: %d\n", recorder.Code)

		bodyReader := recorder.Body
		bodyBytes, err := io.ReadAll(bodyReader)

		fmt.Printf("Response body: %s\n", string(bodyBytes))
		require.Equal(t, http.StatusOK, recorder.Code)

		jsonBuffer := bytes.NewBuffer(nil)
		err = json.Indent(jsonBuffer, bodyBytes, "", "    ")
		require.NoError(t, err)
		fmt.Printf("Formatted body: \n%s\n", jsonBuffer.String())

		resp := handler.Response[operator.GetAccountResult]{}
		err = json.Unmarshal(bodyBytes, &resp)
		require.False(t, resp.Error)
		require.Equal(t, resp.Result.Account.Username, accountName)
	}
	{
		fmt.Printf("=== ListAccounts ===\n")
		reqpath := `/v3/api/accounts/list`
		routepath := `/v3/api/accounts/list`

		rout := router.NewRouter()
		hand := srv.Handler()
		require.NotNil(t, hand)

		req := operator.ListAccountsParams{}
		reqdata, err := json.Marshal(req)
		require.NoError(t, err)

		reqsize := len(reqdata)
		reqsrc := bytes.NewReader(reqdata)

		request, err := http.NewRequest("POST", reqpath, reqsrc)
		require.NoError(t, err)

		request.ContentLength = int64(reqsize)
		request.Header.Set("Content-Type", "application/json")

		recorder := httptest.NewRecorder()
		rout.Post(routepath, hand.ListAccounts)

		rout.ServeHTTP(recorder, request)

		fmt.Printf("Response code: %d\n", recorder.Code)

		bodyReader := recorder.Body
		bodyBytes, err := io.ReadAll(bodyReader)

		fmt.Printf("Response body: %s\n", string(bodyBytes))
		require.Equal(t, http.StatusOK, recorder.Code)

		jsonBuffer := bytes.NewBuffer(nil)
		err = json.Indent(jsonBuffer, bodyBytes, "", "    ")
		require.NoError(t, err)
		fmt.Printf("Formatted body: \n%s\n", jsonBuffer.String())

		resp := handler.Response[operator.ListAccountsResult]{}
		err = json.Unmarshal(bodyBytes, &resp)
		require.False(t, resp.Error)
		require.Equal(t, len(resp.Result.Accounts), 1)
		require.Equal(t, resp.Result.Accounts[0].Username, accountName)
	}
	{
		fmt.Printf("=== DeleteAccount ===\n")
		reqpath := `/v3/api/account/delete`
		routepath := `/v3/api/account/delete`

		rout := router.NewRouter()
		hand := srv.Handler()
		require.NotNil(t, hand)

		req := operator.DeleteAccountParams{
			AccountID: accountID,
		}
		reqdata, err := json.Marshal(req)
		require.NoError(t, err)

		reqsize := len(reqdata)
		reqsrc := bytes.NewReader(reqdata)

		request, err := http.NewRequest("POST", reqpath, reqsrc)
		require.NoError(t, err)

		request.ContentLength = int64(reqsize)
		request.Header.Set("Content-Type", "application/json")

		recorder := httptest.NewRecorder()
		rout.Post(routepath, hand.DeleteAccount)

		rout.ServeHTTP(recorder, request)

		fmt.Printf("Response code: %d\n", recorder.Code)

		bodyReader := recorder.Body
		bodyBytes, err := io.ReadAll(bodyReader)

		fmt.Printf("Response body: %s\n", string(bodyBytes))
		require.Equal(t, http.StatusOK, recorder.Code)

		jsonBuffer := bytes.NewBuffer(nil)
		err = json.Indent(jsonBuffer, bodyBytes, "", "    ")
		require.NoError(t, err)
		fmt.Printf("Formatted body: \n%s\n", jsonBuffer.String())

		resp := handler.Response[operator.DeleteAccountResult]{}
		err = json.Unmarshal(bodyBytes, &resp)
		require.False(t, resp.Error)
	}
	{
		fmt.Printf("=== ListAccounts ===\n")
		reqpath := `/v3/api/accounts/list`
		routepath := `/v3/api/accounts/list`

		rout := router.NewRouter()
		hand := srv.Handler()
		require.NotNil(t, hand)

		req := operator.ListAccountsParams{}
		reqdata, err := json.Marshal(req)
		require.NoError(t, err)

		reqsize := len(reqdata)
		reqsrc := bytes.NewReader(reqdata)

		request, err := http.NewRequest("POST", reqpath, reqsrc)
		require.NoError(t, err)

		request.ContentLength = int64(reqsize)
		request.Header.Set("Content-Type", "application/json")

		recorder := httptest.NewRecorder()
		rout.Post(routepath, hand.ListAccounts)

		rout.ServeHTTP(recorder, request)

		fmt.Printf("Response code: %d\n", recorder.Code)

		bodyReader := recorder.Body
		bodyBytes, err := io.ReadAll(bodyReader)

		fmt.Printf("Response body: %s\n", string(bodyBytes))
		require.Equal(t, http.StatusOK, recorder.Code)

		jsonBuffer := bytes.NewBuffer(nil)
		err = json.Indent(jsonBuffer, bodyBytes, "", "    ")
		require.NoError(t, err)
		fmt.Printf("Formatted body: \n%s\n", jsonBuffer.String())

		resp := handler.Response[operator.ListAccountsResult]{}
		err = json.Unmarshal(bodyBytes, &resp)
		require.False(t, resp.Error)
		require.Equal(t, len(resp.Result.Accounts), 0)
	}

}
