// test-vector-anys -- KEKS test structure with any-types
// Copyright (C) 2024-2025 Sergey Matveev <stargrave@stargrave.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as
// published by the Free Software Foundation, version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this program.  If not, see <http://www.gnu.org/licenses/>.

package main

import (
	"bytes"
	"encoding/hex"
	"fmt"
	"log"
	"math/big"
	"net"
	"strings"
	"time"

	"github.com/google/uuid"
	"go.cypherpunks.su/tai64n/v4"

	"go.cypherpunks.su/keks"
)

func mustHexDec(s string) []byte {
	b, err := hex.DecodeString(s)
	if err != nil {
		panic(err)
	}
	return b
}

func main() {
	bigint80 := new(big.Int).SetBytes(mustHexDec("0100000000000000000000"))
	bigintFF := new(big.Int).SetBytes(mustHexDec("0100000000000000000000000000000000"))
	bigintN80 := new(big.Int).SetBytes(mustHexDec("0100000000000000000000"))
	bigintN80 = bigintN80.Neg(bigintN80)
	bigintNFF := new(big.Int).SetBytes(mustHexDec("0100000000000000000000000000000001"))
	bigintNFF = bigintNFF.Neg(bigintNFF)
	bigintN := new(big.Int).SetBytes(mustHexDec("e5a461280341856d4ad908a69ea5f3ccc10c7882142bb7d801cc380f26b6b4d69632024ee521f8cfafb443d49a2a3d0cc73bb4757e882f5396ed302b418210d0d49d71be86ca699cf5ee3bd6d57ed658e69316229644ba650c92d7f0d4db29c3ad1dfa9979166f4c6e79561a58f8e2c63d08df4e2246ed1f64d2d613a19d8c9a6870e6188e2f3ad40c038fda30452f8ddfcd212a6a974bc25ec6a0564c66a7d28750ff9db458b74441e49ee5e82dbf4974d645678e0ad031f97aaba855451eef17a89b42821e530816dd5793a83b7a82e8ede81e7f3395691f761784f8bc627961cd40845ee908a40b9d1f01927b38eb1a7d4efd60db0944f7ec1b832b7e6eb1833f9a351576ad5de571fae8865da7514f06b0fbf38c1f2a8538f5d38b4e18001ccbb9ddcb488530f6086d14744d8b5672166e48e9ef93772575db66b6f257c6ffad6e2c291510c5ed02e1a8b24b44ec1e2a91686238e8defd18c01998634a5076a6b7f85fc81a1d61a15b2c528dfa082ce3e3e2ca649ac04817ec5c123e0b761ab103f780c014f021bbeb7ea3b86e0ca1c833e38ef5c897a6d7e1f4a2398c490b3d65e2f45c7fae402d1df1698b6fddb185481664871c2664bfd1686b2b3372783f1856f6247a3f8437a2818f68b7c4ea13a5f57b73c72870b684045f15"))
	bigintN = bigintN.Neg(bigintN)

	data := map[string]any{
		"ints": map[string]any{
			"pos": []any{
				uint64(0),
				uint64(1),
				uint64(31),
				uint64(32),
				uint64(123),
				uint64(1234),
				uint64(12345678),
				bigint80,
				bigintFF,
			},
			"neg": []any{
				int64(-1),
				int64(-2),
				int64(-32),
				int64(-33),
				int64(-123),
				int64(-1234),
				int64(-12345678),
				bigintN80,
				bigintNFF,
				bigintN,
			},
		},
		"nil":  nil,
		"bool": []any{true, false},
		"str": map[string]any{
			"bin": []any{
				[]byte{},
				bytes.Repeat([]byte{'0'}, 60),
				bytes.Repeat([]byte{'1'}, 61),
				bytes.Repeat([]byte{'2'}, 255),
				bytes.Repeat([]byte{'A'}, 61+255),
				bytes.Repeat([]byte{'B'}, 62+255),
				bytes.Repeat([]byte{'3'}, 1024),
				bytes.Repeat([]byte{'4'}, 63+255+65535+1),
			},
			"utf8": "привет мир",
		},
		"blob": []any{
			keks.BlobReader{ChunkLen: 12, R: strings.NewReader("5")},
			keks.BlobReader{ChunkLen: 12, R: strings.NewReader(strings.Repeat("6", 12))},
			keks.BlobReader{ChunkLen: 12, R: strings.NewReader(strings.Repeat("7", 13))},
			keks.BlobReader{ChunkLen: 5, R: strings.NewReader("1234567890-")},
		},
		"empties": []any{
			[]any{},
			map[string]any{},
			keks.BlobReader{ChunkLen: 123, R: bytes.NewReader(nil)},
			uuid.Nil,
			tai64n.TAI64(mustHexDec("0000000000000000")),
		},
		"dates": []any{
			time.Unix(1234567890, 0),
			time.Unix(1234567890, 456*1000),
			time.Unix(1234567890, 456789),
			tai64n.TAI64NA(mustHexDec("40000000499602F40006F855075BCD15")),
		},
		"floats": []any{
			keks.Float{NaN: true},
			keks.Float{Pinf: true},
			keks.Float{Ninf: true},
			keks.Float{M: big.NewInt(0), E: big.NewInt(0)},
			keks.Float{M: big.NewInt(-181), E: big.NewInt(-2)},
			keks.Float{M: big.NewInt(5), E: big.NewInt(-5)},
			keks.Float{M: big.NewInt(-8687443681197687), E: big.NewInt(-46)},
			keks.Float{M: big.NewInt(0).SetBytes([]byte{0x27, 0xE4, 0x1B, 0x32, 0x46, 0xBE, 0xC9, 0xB1, 0x6E, 0x39, 0x81, 0x15}), E: big.NewInt(-12345)},
		},
		"uuid": uuid.MustParse("0e875e3f-d385-49eb-87b4-be42d641c367"),
		"ip":   net.ParseIP("2001:db8:85a3:8d3:1319:8a2e:370:7348"),
	}
	var buf bytes.Buffer
	_, err := keks.Encode(&buf, keks.Magic("test-vector"), nil)
	if err != nil {
		log.Fatal(err)
	}
	_, err = keks.Encode(&buf, data, nil)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(hex.EncodeToString(buf.Bytes()))
}
