package service

import (
	"context"
	"fmt"
	"reflect"
	"strconv"

	cda "git.loafle.net/commons_go/di/annotation"
	cdr "git.loafle.net/commons_go/di/registry"
	"git.loafle.net/commons_go/logging"
	oocmci "git.loafle.net/overflow/overflow_commons_go/modules/commons/interfaces"
	sensorConfigM "git.loafle.net/overflow/overflow_commons_go/modules/sensor_config/model"
	"git.loafle.net/overflow/overflow_probes/commons/scheduler"
)

func init() {
	cdr.RegisterType(reflect.TypeOf((*CollectorService)(nil)))
}

type CollectorService struct {
	cda.TypeAnnotation `annotation:"@overFlow:Service()"`
	oocmci.Service

	SensorConfigService *SensorConfigService `annotation:"@Inject()"`
	ContainerService    *ContainerService    `annotation:"@Inject()"`
	CentralService      *CentralService      `annotation:"@Inject()"`

	crawlingScheduler scheduler.Scheduler
}

func (cs *CollectorService) Start() error {
	cs.crawlingScheduler = scheduler.NewScheduler()

	if err := cs.addScheduleAll(); nil != err {
		return err
	}

	schedulerStopCh := cs.crawlingScheduler.Start()
	go func(stopCh chan bool) {
		<-stopCh
		logging.Logger().Infof("Scheduler of collector has been stopped")
	}(schedulerStopCh)

	return nil
}

func (cs *CollectorService) Stop(ctx context.Context) error {

	return nil
}

func (cs *CollectorService) addScheduleAll() error {
	sensorConfigs := cs.SensorConfigService.sensorConfigs
	if nil == sensorConfigs || 0 == len(sensorConfigs) {
		return nil
	}

	for _, sensorConfig := range sensorConfigs {
		interval, err := strconv.ParseUint(sensorConfig.Schedule.Interval, 10, 64)
		if nil != err {
			return fmt.Errorf("Cannot convert interval[%s] %v", sensorConfig.Schedule.Interval, err)
		}
		cs.addSchedule(interval, sensorConfig)
	}

	return nil
}

func (cs *CollectorService) addSchedule(interval uint64, sensorConfig *sensorConfigM.SensorConfig) {
	cs.crawlingScheduler.Every(interval).Seconds().Do(cs.collectTask, sensorConfig)
}

func (cs *CollectorService) collectTask(sensorConfig *sensorConfigM.SensorConfig) {
	go func(_sensorConfig *sensorConfigM.SensorConfig) {
		logging.Logger().Debugf("CollectorService.collectTask for sensor config id[%s] container[%s] crawler[%s]", _sensorConfig.ID.String(), _sensorConfig.Crawler.Container, _sensorConfig.Crawler.Name)
		var result map[string]string
		err := cs.ContainerService.Call(_sensorConfig.Crawler.Container, &result, "CrawlerService.GetData", _sensorConfig.ID.String())
		if nil != err {
			logging.Logger().Errorf("Cannot get data from crawler[%s] of container[%s] %v", _sensorConfig.Crawler.Name, _sensorConfig.Crawler.Container, err)
			return
		}
		logging.Logger().Debugf("Data[%v] received from crawler[%s] of container[%s]", result, _sensorConfig.Crawler.Name, _sensorConfig.Crawler.Container)

	}(sensorConfig)
}
