package sm9

import (
	encoding_asn1 "encoding/asn1"
	"math/big"
	"time"

	"golang.org/x/crypto/cryptobyte"
	cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
	"xdx.jelly/xgcl/gerrors"
	"xdx.jelly/xgcl/gmath"
	oid "xdx.jelly/xgcl/identifier"
	"xdx.jelly/xgcl/sm/sm9/errors"
	"xdx.jelly/xgcl/sm/sm9/internal/bn256"
)

// GM/T 0080 SM9密码算法使用规范
// ASN.1编解码

// GMT/T 0006 OID定义
var (
	OidSm9               = oid.OIDSM9
	OidSm9Sign           = oid.OIDSM9Signature
	OidSm9KeyExchange    = oid.OIDSM9KeyExchange
	OidSm9Encryption     = oid.OIDSM9Encryption
	OidSm9EncryptionEcb  = oid.OIDSM9EncryptionECB
	OidSm9EncryptionCbc  = oid.OIDSM9EncryptionCBC
	OidSm9EncryptionCfb  = oid.OIDSM9EncryptionCFB
	OidSm9EncryptionOfb  = oid.OIDSM9EncryptionOFB
	OidSM9KeyEncupsulate = oid.OIDSM9KeyEncupsulate
)

const numBytes = 32

// Identifier GM/T 0090定义身份标识
//
// deprecated: Identifier moves to package xdx.jelly/xibc
type Identifier struct {
	// 标准中多了一个explicit
	Version      int `asn1:"default:0"`
	IdentityType encoding_asn1.ObjectIdentifier
	Alias        string `asn1:"utf8"`
	IdentityData []byte
	Serial       *big.Int  `asn1:"optional,explicit,tag:0"`
	ValidStart   time.Time `asn1:"generalized"`
	ValidEnd     time.Time `asn1:"optional,explicit,generalized,tag:1"`
	IdExtentions []byte    `asn1:"optional,explicit,tag:2"`
}

func (id *Identifier) MarshalASN1() ([]byte, error) {
	return encoding_asn1.Marshal(*id)
}

func (id *Identifier) UnmarshalASN1(b []byte) (rest []byte, err error) {
	return encoding_asn1.Unmarshal(b, id)
}

////////////////////////////////////////////////////////////////
//
//						主签名密钥
//
////////////////////////////////////////////////////////////////

func (k *MastSignPrivateKey) MarshalASN1() ([]byte, error) {
	var b cryptobyte.Builder
	b.AddASN1BigInt(&k.Int)
	return b.Bytes()
}

func (k *MastSignPrivateKey) UnmarshalASN1(data []byte) (rest []byte, err error) {
	input := cryptobyte.String(data)
	ok := input.ReadASN1Integer(&k.Int)
	if !ok {
		return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse MastSignPrivateKey failed, read ASN.1 Integer error")
	}
	return []byte(input), nil
}

// MarshalASN1 返回ASN.1编码，如果compressed为true，则返回的是压缩形式
//
// 注：不支持混合形式输出
func (k *MastSignPublicKey) MarshalASN1(compressed bool) ([]byte, error) {
	return k.G2.MarshalASN1(compressed)
}

// UnmarshalASN1 ASN.1解码MastSignPublicKey
//
// 注：支持tag为0,2,3,4,6,7即无穷远点(0)，非压缩形式(4)，压缩形式(2,3)，混合形式(6,7)
func (k *MastSignPublicKey) UnmarshalASN1(data []byte) (rest []byte, err error) {
	return k.G2.UnmarshalASN1(data)
}

////////////////////////////////////////////////////////////////
//
//						主加密密钥
//
////////////////////////////////////////////////////////////////

func (k *MastEncPrivateKey) MarshalASN1() ([]byte, error) {
	var b cryptobyte.Builder
	b.AddASN1BigInt(&k.Int)
	return b.Bytes()
}

func (k *MastEncPrivateKey) UnmarshalASN1(data []byte) (rest []byte, err error) {
	input := cryptobyte.String(data)
	ok := input.ReadASN1Integer(&k.Int)
	if !ok {
		return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse MastEncPrivateKey failed, read ASN.1 Integer error")
	}
	return []byte(input), nil
}

// MarshalASN1 返回ASN.1编码，如果compressed为true，则返回的是压缩形式
//
// 注：不支持混合形式
func (k *MastEncPublicKey) MarshalASN1(compressed bool) ([]byte, error) {
	return k.G1.MarshalASN1(compressed)
}

// UnmarshalASN1 ASN.1解码MastSignPublicKey
//
// 注：支持tag为0,2,3,4,6,7即无穷远点(0)，非压缩形式(4)，压缩形式(2,3)，混合形式(6,7)
func (k *MastEncPublicKey) UnmarshalASN1(data []byte) (rest []byte, err error) {
	return k.G1.UnmarshalASN1(data)
}

////////////////////////////////////////////////////////////////
//
//						用户密钥
//
////////////////////////////////////////////////////////////////

func (u *UserSignKey) MarshalASN1(compressed bool) ([]byte, error) {
	return u.G1.MarshalASN1(compressed)
}

func (u *UserSignKey) UnmarshalASN1(data []byte) (rest []byte, err error) {
	return u.G1.UnmarshalASN1(data)
}

func (u *UserEncKey) MarshalASN1(compressed bool) ([]byte, error) {
	return u.G2.MarshalASN1(compressed)

}

func (u *UserEncKey) UnmarshalASN1(data []byte) (rest []byte, err error) {
	return u.G2.UnmarshalASN1(data)
}

////////////////////////////////////////////////////////////////
//
//						签名结构
//
////////////////////////////////////////////////////////////////

// SM9Signature ::= SEQUENCE{
// 	H	OCTET STRING,	——杂凑分量，算法是H2（见GB/T 38635.2—2020）
// 	S	BIT STRING   	——签名结果（见GB/T 38635.2—2020）
// }

func (s *Signature) MarshalASN1(compressed bool) ([]byte, error) {
	var b cryptobyte.Builder
	h := make([]byte, numBytes)
	err := gmath.FillBytes(&s.H, h)
	if err != nil {
		return nil, gerrors.WithAnnotating(
			gerrors.ChainErrors(errors.ErrDecodeASN1Failed, err),
			"Signature.H is bigger than 256 bits",
		)
	}

	b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
		b.AddASN1OctetString(h)
		b.AddASN1BitString(bn256.MarshalG1(&s.S, compressed))
	})

	return b.Bytes()
}

func (s *Signature) UnmarshalASN1(data []byte) (rest []byte, err error) {
	input := cryptobyte.String(data)
	var inner, hBytes cryptobyte.String
	var sBitString encoding_asn1.BitString
	if !input.ReadASN1(&inner, cryptobyte_asn1.SEQUENCE) ||
		inner.Empty() ||
		!inner.ReadASN1(&hBytes, cryptobyte_asn1.OCTET_STRING) ||
		!inner.ReadASN1BitString(&sBitString) ||
		!inner.Empty() {
		return data, errors.ErrDecodeASN1Failed
	}
	s.H.SetBytes(hBytes)
	_, err = bn256.UnmarshalG1(&s.S, sBitString.RightAlign())
	if err != nil {
		return data, err
	}
	return []byte(input), err
}

////////////////////////////////////////////////////////////////
//
//						密文结构
//
////////////////////////////////////////////////////////////////

// SM9Cipher ::= SEQUENCE{
// 	EnType	INTEGER,	——加密方式
// 	C1	BIT STRING,	——密文第一部分C1（见GB/T 38635.2—2020）
// 	C3	OCTET STRING,	——密文杂凑值
// 	C2	OCTET STRING 	——密文
// }

func (c *Cipher) MarshalASN1(compressed bool) ([]byte, error) {
	var b cryptobyte.Builder
	c2Bytes := make([]byte, len(c.C)+len(c.IV))
	n := 0
	if c.EncType > 1 {
		n += copy(c2Bytes, c.IV[:])
	}
	n += copy(c2Bytes[n:], c.C)
	c2Bytes = c2Bytes[:n]

	b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
		b.AddASN1Int64(int64(c.EncType))
		b.AddASN1BitString(bn256.MarshalG1(&c.C1, compressed))
		b.AddASN1OctetString(c.H[:])
		b.AddASN1OctetString(c2Bytes)
	})
	return b.Bytes()
}

func (c *Cipher) UnmarshalASN1(data []byte) (rest []byte, err error) {
	input := cryptobyte.String(data)
	var inner, c3Bytes, c2Bytes cryptobyte.String
	var c1BitString encoding_asn1.BitString
	var encType uint32
	if !input.ReadASN1(&inner, cryptobyte_asn1.SEQUENCE) ||
		!inner.ReadASN1Integer(&encType) ||
		!inner.ReadASN1BitString(&c1BitString) ||
		!inner.ReadASN1(&c3Bytes, cryptobyte_asn1.OCTET_STRING) ||
		!inner.ReadASN1(&c2Bytes, cryptobyte_asn1.OCTET_STRING) ||
		!inner.Empty() {
		return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse Cipher ASN.1 data failed")
	}
	c.EncType = EncType(encType)
	_, err = bn256.UnmarshalG1(&c.C1, c1BitString.RightAlign())
	if err != nil {
		return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse Cipher ASN.1 data failed")
	}
	if len(c3Bytes) != len(c.H) {
		return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse Cipher ASN.1 data failed")
	}
	copy(c.H[:], c3Bytes)

	if c.EncType > 1 {
		if len(c2Bytes) < len(c.IV) {
			return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse Cipher ASN.1 data failed")
		}
		copy(c.IV[:], c2Bytes)
		c2Bytes = c2Bytes[len(c.IV):]
	}
	c.C = append(c.C[:0], c2Bytes...)
	return []byte(input), nil
}

////////////////////////////////////////////////////////////////
//
//						密文封装结构
//
////////////////////////////////////////////////////////////////

// SM9KeyPackage ::= SEQUENCE{
// 	K	OCTET STRING,	——生成的密钥
// 	C	BIT STRING	——封装的交换密文
// }
// K作为用户A保留的密钥。C作为交换密文传递给B用户，B用户利用C可以生成K。

// 这里与标准不同，只是封装C. 密钥不进行封装。即
//
//	SM9KeyPackage := OCTET STRING
func (k *KeyPackage) MarshalASN1(compressed bool) ([]byte, error) {
	var b cryptobyte.Builder
	b.AddASN1BitString(bn256.MarshalG1(&k.G1, compressed))
	return b.Bytes()
}

func (k *KeyPackage) UnmarshalASN1(data []byte) (rest []byte, err error) {
	input := cryptobyte.String(data)
	var b encoding_asn1.BitString
	if ok := input.ReadASN1BitString(&b); !ok {
		return data, gerrors.WithAnnotating(errors.ErrDecodeASN1Failed, "parse KeyPackage ASN.1 data failed")
	}
	_, err = bn256.UnmarshalG1(&k.G1, b.RightAlign())
	if err != nil {
		return data, gerrors.WithAnnotating(
			gerrors.ChainErrors(errors.ErrDecodeASN1Failed, err),
			"parse KeyPackage ASN.1 data failed",
		)
	}
	return []byte(input), nil
}
