package rfctime

import (
	"fmt"
	"gogs.mikescher.com/BlackForestBytes/goext/langext"
	"strconv"
	"strings"
	"time"
)

type Time struct {
	Hour       int
	Minute     int
	Second     int
	NanoSecond int
}

func (t Time) Serialize() string {
	return fmt.Sprintf("%04d:%02d:%02d.%09d", t.Hour, t.Minute, t.Second, t.NanoSecond)
}

func (t Time) SerializeShort() string {
	if t.NanoSecond == 0 && t.Second == 0 {
		return fmt.Sprintf("%02d:%02d", t.Hour, t.Minute)
	} else if t.NanoSecond == 0 {
		return fmt.Sprintf("%02d:%02d:%02d", t.Hour, t.Minute, t.Second)
	} else {
		return fmt.Sprintf("%02d:%02d:%02d.%09d", t.Hour, t.Minute, t.Second, t.NanoSecond)
	}
}

func (t *Time) Deserialize(v string) error {

	var h, m, s, ns string

	split1 := strings.Split(v, ".")

	if len(split1) == 2 {

		split2 := strings.Split(split1[0], ":")
		if len(split2) == 3 {

			h = split2[0]
			m = split2[1]
			s = split2[2]
			ns = split1[1]

		} else {
			return fmt.Errorf("invalid time format: %s", v)
		}

	} else if len(split1) == 1 {

		split2 := strings.Split(split1[0], ":")
		if len(split2) == 2 {

			h = split2[0]
			m = split2[1]
			s = "0"
			ns = "0"

		} else if len(split2) == 3 {

			h = split2[0]
			m = split2[1]
			s = split2[2]
			ns = "0"

		} else {
			return fmt.Errorf("invalid time format: %s", v)
		}

	} else {
		return fmt.Errorf("invalid time format: %s", v)
	}

	ns = langext.StrPadRight(ns, "0", 9)

	hh, err := strconv.ParseInt(h, 10, 32)
	if err != nil {
		return fmt.Errorf("invalid time format: %s", v)
	}

	mm, err := strconv.ParseInt(m, 10, 32)
	if err != nil {
		return fmt.Errorf("invalid time format: %s", v)
	}

	ss, err := strconv.ParseInt(s, 10, 32)
	if err != nil {
		return fmt.Errorf("invalid time format: %s", v)
	}

	nss, err := strconv.ParseInt(ns, 10, 32)
	if err != nil {
		return fmt.Errorf("invalid time format: %s", v)
	}

	t.Hour = int(hh)
	t.Minute = int(mm)
	t.Second = int(ss)
	t.NanoSecond = int(nss)

	return nil
}

func (t Time) FormatStr() string {
	return "15:04:05.999999999"
}

func (t Time) GoString() string {
	return fmt.Sprintf("rfctime.NewTime(%d, %d, %d, %d)", t.Hour, t.Minute, t.Second, t.NanoSecond)
}

func (t Time) String() string {
	return fmt.Sprintf("%04d:%02d:%02d.%09d", t.Hour, t.Minute, t.Second, t.NanoSecond)
}

func NewTime(h int, m int, s int, ns int) Time {
	return Time{
		Hour:       h,
		Minute:     m,
		Second:     s,
		NanoSecond: ns,
	}
}

func NewTimeFromTS(t time.Time) Time {
	return Time{
		Hour:       t.Hour(),
		Minute:     t.Minute(),
		Second:     t.Second(),
		NanoSecond: t.Nanosecond(),
	}
}

func NowTime(loc *time.Location) Time {
	now := time.Now().In(loc)
	return NewTime(now.Hour(), now.Minute(), now.Second(), now.Nanosecond())
}

func NowTimeLoc() Time {
	return NowTime(time.UTC)
}

func NowTimeUTC() Time {
	return NowTime(time.Local)
}