package icssvc

import (
	"fmt"
	"os"
	"sync"
	"time"

	"gitlab.com/cinnamon/voiceagent/icsconf"
	"gitlab.com/cinnamon/voiceagent/icserror"
	"gitlab.com/cinnamon/voiceagent/icslog"
	"gitlab.com/cinnamon/voiceagent/icsutil"
)

const (
	COMPANY_NAME = "iComsys"
	VERSION      = "1.0.0"
	BUILD_DATE   = ""
)

const (
	ONEMB = 1048576
)

type IcsService struct {
	isExit bool //exit service
	isStop bool //pause service

	log    *icslog.IcsLog
	config *icsconf.IcsConfig
	//homeDir string
}

var ServiceStatus *IcsService
var once sync.Once

func GetServiceStatus() *IcsService {
	once.Do(func() {
		ServiceStatus = &IcsService{isExit: false, isStop: false}
	})
	return ServiceStatus
}

func NewService() *IcsService {
	return GetServiceStatus()
}

func (s *IcsService) Exit(start bool) {
	i := GetServiceStatus()
	i.isExit = start
}

func (s IcsService) GetExit() bool {
	return s.isExit
}

func (s *IcsService) Stop(stop bool) {
	i := GetServiceStatus()
	i.isStop = stop
}

func (s IcsService) GetStop() bool {
	return s.isStop
}

func (s *IcsService) SetIcsConfig(conf *icsconf.IcsConfig) *icserror.IcsError {
	if conf == nil {
		return icserror.ICSERRInvalidParam
	}
	s.config = conf

	return nil
}

func (s IcsService) GetIcsConfig() *icsconf.IcsConfig {
	//fmt.Println(s.config)
	return s.config
}

func (s *IcsService) SetIcsLog(log *icslog.IcsLog) {
	s.log = log
}

func (s IcsService) GetIcsLog() (log *icslog.IcsLog) {
	return s.log
}

func (s IcsService) ShowServiceInfo() (info string) {
	info = fmt.Sprintf("%s Voice Agent version %s\nCopyright (C) 2022 %s\n\n", COMPANY_NAME, VERSION, COMPANY_NAME)
	fmt.Printf("%s Voice Agent version %s\nCopyright (C) 2022 %s\n\n", COMPANY_NAME, VERSION, COMPANY_NAME)

	return info
}

func (s IcsService) getMonth2Int(mon time.Month) int {
	switch mon {
	case time.January:
		return 1
	case time.February:
		return 2
	case time.March:
		return 3
	case time.April:
		return 4
	case time.May:
		return 5
	case time.June:
		return 6
	case time.July:
		return 7
	case time.August:
		return 8
	case time.September:
		return 9
	case time.October:
		return 10
	case time.November:
		return 11
	case time.December:
		return 12
	}

	return -1
}

func (s IcsService) GetRemainExpire() (int, *icserror.IcsError) {
	if s.config == nil {
		return -1, icserror.ICSERRInvalidParam
	}

	var rem int

	currentTime := time.Now()

	yy := currentTime.Year()
	mm := currentTime.Month()
	intmm := s.getMonth2Int(mm)
	if intmm != -1 {
		expire := s.config.GetExpire()
		//since 2018.01
		rem = expire - (((yy - 2018) * 12) + intmm)
	} else {
		return -1, icserror.ICSERRSVCTime
	}

	return rem, nil
}

/////////////////////////////
func (s IcsService) LogWatcher() *icserror.IcsError {
	l := icslog.GetIcsLog()
	l.Print(icslog.LOG_LEVEL_INFO, -1, "Log Watcher Start")

	for !s.GetExit() {
		for s.GetStop() {
			time.Sleep(time.Millisecond)
		}

		//check log file date
		y1, m1, d1 := s.log.CurrentDate.Date()
		y2, m2, d2 := time.Now().Date()
		h2, mi2, ss2 := time.Now().Hour(), time.Now().Minute(), time.Now().Second()

		if h2 == l.DelHour && mi2 == 0 && ss2 == 0 {
			go l.RecvDelLog()
			time.Sleep(time.Second)
		}

		if h2 == icsconf.GetIcsConfig().VoiceConfig.DelVConfig.DelVHour && mi2 == 0 && ss2 == 0 {
			icslog.DelVoice()
			time.Sleep(time.Second)
		}

		if d1 != d2 || y1 != y2 || m1 != m2 {
			s.config = icsconf.GetIcsConfig()
			logpath := fmt.Sprintf("%s", s.config.LogConfig.Path)
			aSpace := icsutil.GetDiskAvailableSpace(logpath)
			if aSpace < uint64(s.config.LogConfig.Disklimit*ONEMB) {
				return icserror.ICSERRUTILDiskFull
			}

			s.log.M.Lock()

			//save and close old log file
			s.log.LogFile.Sync()
			s.log.LogFile.Close()

			//create new log file
			s.log.CurrentDate = time.Now()
			/*
				fmt.Println(s.log)
				fmt.Println(s.log.LogFileName)
				fmt.Println(s.config)
				fmt.Println(s.config.GetHomeDir())
				fmt.Println(s.log.Path)
				fmt.Println(y2)
				fmt.Println(m2)
				fmt.Println(d2)
			*/
			s.log.LogFileName = fmt.Sprintf("%s/icsbot.log-%d%02d%02d", s.log.Path, y2, m2, d2)
			var oerr error
			s.log.LogFile, oerr = os.OpenFile(s.log.LogFileName, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
			if oerr != nil {
				icserror.ICSERRFileOpen.SetError(oerr)
				//icserror.ICSERRFileOpen.PrintWithCaller(1)

				s.log.M.Unlock()
				return icserror.ICSERRFileOpen
			}

			s.log.M.Unlock()
			l.Printf(icslog.LOG_LEVEL_INFO, -1, "Log Watcher: Updated Log File - %s", s.log.LogFileName)
		}

		//l.Printf(icslog.LOG_LEVEL_INFO, -1, "Log Watcher")
		time.Sleep(time.Millisecond)
	}

	return nil
}