package log

import (
	"bytes"
	"encoding/binary"
	"fmt"
	"git.nspix.com/golang/micro/helper/pool/bufferpool"
	"net"
	"os"
	"time"
)

type LogHub struct {
	level   int
	appName string
	prefix  string
	conn    *net.UDPConn
}

func (lg *LogHub) SetLevel(i int) {
	lg.level = i
}

func (lg *LogHub) Prefix(s string) {
	lg.prefix = s
}

func (lg *LogHub) Print(i ...interface{}) {
	lg.write(TraceLevel, fmt.Sprint(i...))
}

func (lg *LogHub) Printf(format string, args ...interface{}) {
	lg.write(TraceLevel, fmt.Sprintf(format, args...))
}

func (lg *LogHub) Debug(i ...interface{}) {
	lg.write(DebugLevel, fmt.Sprint(i...))
}

func (lg *LogHub) Debugf(format string, args ...interface{}) {
	lg.write(DebugLevel, fmt.Sprintf(format, args...))
}

func (lg *LogHub) Info(i ...interface{}) {
	lg.write(InfoLevel, fmt.Sprint(i...))
}

func (lg *LogHub) Infof(format string, args ...interface{}) {
	lg.write(InfoLevel, fmt.Sprintf(format, args...))
}

func (lg *LogHub) Warn(i ...interface{}) {
	lg.write(WarnLevel, fmt.Sprint(i...))
}

func (lg *LogHub) Warnf(format string, args ...interface{}) {
	lg.write(WarnLevel, fmt.Sprintf(format, args...))
}

func (lg *LogHub) Error(i ...interface{}) {
	lg.write(ErrorLevel, fmt.Sprint(i...))
}

func (lg *LogHub) Errorf(format string, args ...interface{}) {
	lg.write(ErrorLevel, fmt.Sprintf(format, args...))
}

func (lg *LogHub) Fatal(i ...interface{}) {
	lg.write(FatalLevel, fmt.Sprint(i...))
}

func (lg *LogHub) Fatalf(format string, args ...interface{}) {
	lg.write(FatalLevel, fmt.Sprintf(format, args...))
}

func (lg *LogHub) Panic(i ...interface{}) {
	lg.write(PanicLevel, fmt.Sprint(i...))
}

func (lg *LogHub) Panicf(format string, args ...interface{}) {
	lg.write(PanicLevel, fmt.Sprintf(format, args...))
}

func (lg *LogHub) write(level int, s string) {
	if lg.level > level {
		return
	}
	var (
		ls string
		bf *bytes.Buffer
	)
	if lg.prefix != "" {
		ls += " [" + lg.prefix + "] "
	}
	ls += s
	bf = bufferpool.Get()
	defer bufferpool.Put(bf)
	// | 1byte level | 8 bytes timestamp | 1 byte name length | n byte name | 2 byte content length | n byte content |
	bf.WriteByte(uint8(level))
	_ = binary.Write(bf, binary.LittleEndian, uint64(time.Now().Unix()))
	bf.WriteByte(uint8(len(lg.appName)))
	bf.WriteString(lg.appName)
	_ = binary.Write(bf, binary.LittleEndian, uint16(len(ls)))
	bf.WriteString(ls)
	bf.WriteTo(lg.conn)
}

func NewLogHub(addr string) Logger {
	var (
		err     error
		udpAddr *net.UDPAddr
	)
	if udpAddr, err = net.ResolveUDPAddr("udp", addr); err != nil {
		return NewConsoleLogger()
	}
	hub := &LogHub{
		appName: os.Getenv("MICRO_SERVICE_NAME"),
	}
	hub.conn, err = net.DialUDP("udp", nil, udpAddr)
	return hub
}
