package svc

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"testing"

	"git.simanc.com/software/golib/v4/features/mo"
	"git.simanc.com/software/golib/v4/gio"
	"git.simanc.com/software/golib/v4/gnet"
)

func TestHttpHandler_ServeHTTP(t *testing.T) {
	mux := http.NewServeMux()
	mux.Handle("/svc/", &HttpHandler{Items: service.Items, User: testUser})
	err := http.ListenAndServe("127.0.0.1:7000", mux)
	if err != nil {
		t.Error(err)
		return
	}
}

const (
	testGlobalItemName = "test.user"
)

func TestHttpHandlerCmdInsertOne(t *testing.T) {
	body := httpHandleBody{
		Data: map[string]any{"name": "TestHttpHandlerCmdInsertOne", "age": 20, "gender": "Male", "phone": "11111111111", "company": mo.A{111, 222}},
	}
	resp, err := testHTTPHandle(cmdInsertOne, body)
	if err != nil {
		t.Error(err)
		return
	}
	t.Log("cmd:", resp.CMD)
	t.Log("itemName:", resp.ItemName)
	t.Log("data:", resp.Data)
}

func TestHttpHandlerCmdInsertMany(t *testing.T) {
	body := httpHandleBody{
		Data: []any{
			map[string]any{"name": "TestHttpHandlerCmdInsertMany", "age": 21, "gender": "Male", "phone": "11111111111", "company": mo.A{111, 222}},
			map[string]any{"name": "TestHttpHandlerCmdInsertMany", "age": 21, "gender": "Male", "phone": "11111111111", "company": mo.A{111, 222}},
		},
	}
	resp, err := testHTTPHandle(cmdInsertMany, body)
	if err != nil {
		t.Error(err)
		return
	}
	t.Log("cmd:", resp.CMD)
	t.Log("itemName:", resp.ItemName)
	t.Log("data:", resp.Data)
}

func TestHttpHandlerCmdUpdateOne(t *testing.T) {
	body := httpHandleBody{
		Data:    map[string]any{"name": "TestHttpHandlerCmdInsertOne"},
		ExtData: map[string]any{"phone": "updated One"},
	}
	resp, err := testHTTPHandle(cmdUpdateOne, body)
	if err != nil {
		t.Error(err)
		return
	}
	t.Log("cmd:", resp.CMD)
	t.Log("itemName:", resp.ItemName)
	t.Log("data:", resp.Data)
}

func TestHttpHandlerCmdUpdateByID(t *testing.T) {
	body := httpHandleBody{
		Data:    "649e1f9ed159267e8f2ffdf5",
		ExtData: map[string]any{"phone": "updated by id"},
	}
	resp, err := testHTTPHandle(cmdUpdateById, body)
	if err != nil {
		t.Error(err)
		return
	}
	t.Log("cmd:", resp.CMD)
	t.Log("itemName:", resp.ItemName)
	t.Log("data:", resp.Data)
}

func TestHttpHandlerCmdUpdateMany(t *testing.T) {
	body := httpHandleBody{
		Data:    map[string]any{"name": "TestHttpHandlerCmdInsertMany"},
		ExtData: map[string]any{"phone": "updated Many"},
	}
	resp, err := testHTTPHandle(cmdUpdateMany, body)
	if err != nil {
		t.Error(err)
		return
	}
	t.Log("cmd:", resp.CMD)
	t.Log("itemName:", resp.ItemName)
	t.Log("data:", resp.Data)
}

func TestHttpHandlerCmdFindOne(t *testing.T) {
	body := httpHandleBody{
		Data: map[string]any{"name": map[string]any{"$regex": "Test"}, "age": 20},
	}
	resp, err := testHTTPHandle(cmdFindOne, body)
	if err != nil {
		t.Error(err)
		return
	}
	t.Log("cmd:", resp.CMD)
	t.Log("itemName:", resp.ItemName)
	t.Log("data:", resp.Data)
}

func TestHttpHandlerCmdFind(t *testing.T) {
	body := httpHandleBody{
		Data: map[string]any{"age": map[string]any{"$gte": 20}},
	}
	resp, err := testHTTPHandle(cmdFind, body)
	if err != nil {
		t.Error(err)
		return
	}
	t.Log("cmd:", resp.CMD)
	t.Log("itemName:", resp.ItemName)
	for i, row := range resp.Data.([]any) {
		t.Logf("data[%d]: %v\n", i, row)
	}
}

func TestHttpHandlerCmdDeleteOne(t *testing.T) {
	body := httpHandleBody{
		Data: map[string]any{"name": "TestHttpHandlerCmdInsertOne"},
	}
	resp, err := testHTTPHandle(cmdDeleteOne, body)
	if err != nil {
		t.Error(err)
		return
	}
	t.Log("cmd:", resp.CMD)
	t.Log("itemName:", resp.ItemName)
	t.Log("data:", resp.Data)
}

func TestHttpHandlerCmdDeleteMany(t *testing.T) {
	body := httpHandleBody{
		Data: map[string]any{"name": map[string]any{"$regex": "Test"}},
	}
	resp, err := testHTTPHandle(cmdDeleteMany, body)
	if err != nil {
		t.Error(err)
		return
	}
	t.Log("cmd:", resp.CMD)
	t.Log("itemName:", resp.ItemName)
	t.Log("data:", resp.Data)
}

func testHTTPHandle(cmd string, body httpHandleBody) (*httpHandleBody, error) {
	b, err := json.Marshal(body)
	if err != nil {
		return nil, fmt.Errorf("json.Marshal: %s", err)
	}
	uri := fmt.Sprintf("http://127.0.0.1:7000/svc/%s/%s", cmd, testGlobalItemName)
	resp, err := http.Post(uri, gnet.HTTPContentTypeJson, bytes.NewReader(b))
	if err != nil {
		return nil, fmt.Errorf("http.Post: %s", err)
	}
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("http.Post: StatusCode: %d", resp.StatusCode)
	}
	p, err := gio.ReadLimit(resp.Body, 0)
	if err != nil {
		return nil, fmt.Errorf("ReadResponseBody: %s", err)
	}
	var respBody httpHandleBody
	if err = json.Unmarshal(p, &respBody); err != nil {
		return nil, fmt.Errorf("json.Unmarshal: %s", err)
	}
	return &respBody, nil
}
