package asn1obj

import (
	"encoding/asn1"
	"time"
)

// GeneralizedTime returns the specified time as a GeneralizedTime
func GeneralizedTime(t time.Time) []byte {
	// should never error
	asn1result, err := asn1.MarshalWithParams(t, "generalized")
	if err != nil {
		panic(err)
	}

	return asn1result
}

// helper funcs from golang asn1 package
func appendTwoDigits(dst []byte, v int) []byte {
	return append(dst, byte('0'+(v/10)%10), byte('0'+v%10))
}

func appendFourDigits(dst []byte, v int) []byte {
	var bytes [4]byte
	for i := range bytes {
		bytes[3-i] = '0' + byte(v%10)
		v /= 10
	}
	return append(dst, bytes[:]...)
}

// generalizedTimevalue returns the specified time encoded as a
// GeneralizedTime but WITHOUT the ASN.1 headers (class/tag/length)
func generalizedTimevalue(t time.Time) []byte {
	dst := []byte{}

	year := t.Year()
	if year < 0 || year > 9999 {
		panic("cannot represent time as GeneralizedTime (invalid year)")
	}

	dst = appendFourDigits(dst, year)

	_, month, day := t.Date()

	dst = appendTwoDigits(dst, int(month))
	dst = appendTwoDigits(dst, day)

	hour, min, sec := t.Clock()

	dst = appendTwoDigits(dst, hour)
	dst = appendTwoDigits(dst, min)
	dst = appendTwoDigits(dst, sec)

	_, offset := t.Zone()

	switch {
	case offset/60 == 0:
		return append(dst, 'Z')
	case offset > 0:
		dst = append(dst, '+')
	case offset < 0:
		dst = append(dst, '-')
	}

	offsetMinutes := offset / 60
	if offsetMinutes < 0 {
		offsetMinutes = -offsetMinutes
	}

	dst = appendTwoDigits(dst, offsetMinutes/60)
	dst = appendTwoDigits(dst, offsetMinutes%60)

	return dst
}

// helper funcs from golang asn1 package - END

// GeneralizedTimeExplicitValue returns t encoded as a GeneralizedTime, however
// instead of tagging it with GeneralizedTime it is instead tagged with an
// explicit tag of the specified tag number
func GeneralizedTimeExplicitValue(explicitTagNumber int, t time.Time) []byte {
	return ExplicitValue(explicitTagNumber, generalizedTimevalue(t))
}