/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package hessian

import (
	"fmt"
	"reflect"
	"testing"
)

import (
	big "github.com/dubbogo/gost/math/big"

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

func TestEncodeDecodeDecimal(t *testing.T) {
	var dec big.Decimal
	_ = dec.FromString("100.256")
	e := NewEncoder()
	err := e.Encode(dec)
	if err != nil {
		t.Error(err)
		t.FailNow()
	}

	d := NewDecoder(e.buffer)
	decObj, err := d.Decode()
	if err != nil {
		t.Error(err)
		t.FailNow()
	}

	if !reflect.DeepEqual(dec.String(), decObj.(*big.Decimal).String()) {
		t.Errorf("expect: %v, but get: %v", dec, decObj)
	}
}

func TestDecimalGoDecode(t *testing.T) {
	var d big.Decimal
	_ = d.FromString("100.256")
	d.Value = d.String()
	doTestStringer(t, "customReplyTypedFixedDecimal", "100.256")
}

func TestDecimalJavaDecode(t *testing.T) {
	var d big.Decimal
	_ = d.FromString("100.256")
	d.Value = d.String()
	testJavaDecode(t, "customArgTypedFixed_Decimal", d)
}

func TestEncodeDecodeInteger(t *testing.T) {
	var bigInt bigInteger
	// bigInt := new(bigInteger)
	_ = bigInt.FromString("100256")
	e := NewEncoder()
	err := e.Encode(bigInt)
	if err != nil {
		t.Error(err)
		t.FailNow()
	}

	d := NewDecoder(e.buffer)
	bigIntObj, err := d.Decode()
	if err != nil {
		t.Error(err)
		t.FailNow()
	}

	if !reflect.DeepEqual(bigInt.String(), bigIntObj.(*bigInteger).String()) {
		t.Errorf("expect: %v, but get: %v", bigInt, bigIntObj)
	}
}

func TestIntegerGoDecode(t *testing.T) {
	doTestStringer(t, "customReplyTypedFixedIntegerZero", "0")
	doTestStringer(t, "customReplyTypedFixedInteger", "4294967298")
	doTestStringer(t, "customReplyTypedFixedIntegerSigned", "-4294967298")
}

func TestIntegerJavaDecode(t *testing.T) {
	var i bigInteger
	_ = i.FromString("4294967298")
	testJavaDecode(t, "customArgTypedFixed_Integer", i)

	_ = i.FromString("0")
	testJavaDecode(t, "customArgTypedFixed_IntegerZero", i)

	_ = i.FromString("-4294967298")
	testJavaDecode(t, "customArgTypedFixed_IntegerSigned", i)
}

func TestIntegerListGoDecode(t *testing.T) {
	data := []string{
		"1234",
		"12347890",
		"123478901234",
		"1234789012345678",
		"123478901234567890",
		"1234789012345678901234",
		"12347890123456789012345678",
		"123478901234567890123456781234",
		"1234789012345678901234567812345678",
		"12347890123456789012345678123456781234",
		"-12347890123456789012345678123456781234",
		"0",
	}

	out, err := decodeJavaResponse(`customReplyTypedFixedList_BigInteger`, ``, false)
	if err != nil {
		t.Errorf("%#v %v", out, err)
		return
	}

	resp := out.([]*big.Integer)
	for i := range data {
		gotInteger := resp[i]
		if gotInteger.String() != data[i] {
			t.Errorf("java: %s go: %s", gotInteger.String(), data[i])
		}
	}
}

func doTestStringer(t *testing.T, method, content string) {
	testDecodeFrameworkFunc(t, method, func(r interface{}) {
		t.Logf("%#v", r)
		assert.Equal(t, content, r.(fmt.Stringer).String())
	})
}

func TestDecimalListGoDecode(t *testing.T) {
	data := []string{
		"123.4",
		"123.45",
		"123.456",
	}

	out, err := decodeJavaResponse(`customReplyTypedFixedList_BigDecimal`, ``, false)
	if err != nil {
		t.Error(err)
		return
	}

	resp := out.([]*big.Decimal)
	for i := range data {
		gotDecimal := resp[i]
		if gotDecimal.String() != data[i] {
			t.Errorf("java: %s go: %s", gotDecimal.String(), data[i])
		}
	}
}

func TestCustomReplyObjectJsonObjectBigDecimalDecode(t *testing.T) {
	decimal := &big.Decimal{}
	_ = decimal.FromString("100")

	out, err := decodeJavaResponse(`customReplyObjectJsonObjectBigDecimal`, ``, false)
	if err != nil {
		t.Error(err)
		return
	}

	res := out.(map[interface{}]interface{})
	assert.Equal(t, 1, len(res))

	dec := res["test_BigDecimal"].(*big.Decimal)
	assert.Equal(t, decimal.String(), dec.String())
}

func TestObjectListGoDecode(t *testing.T) {
	data := []string{
		"1234",
		"-12347890",
		"0",
		"123.4",
		"-123.45",
		"0",
	}

	out, err := decodeJavaResponse(`customReplyTypedFixedList_CustomObject`, ``, false)
	if err != nil {
		t.Error(err)
		return
	}

	resp := out.([]Object)
	for i := range data {
		elem := resp[i]
		if elem.(fmt.Stringer).String() != data[i] {
			t.Logf("%T %#v", elem, elem)
			t.Errorf("java: %s go: %s", elem.(fmt.Stringer).String(), data[i])
		}
	}
}
