package mobile

import (
	"openreplay/backend/pkg/handlers"
	. "openreplay/backend/pkg/messages"
)

/*
	Handler name: PerformanceAggregator
	Input events: MobilePerformanceEvent,
				  MobileSessionEnd
	Output event: IssueEvent
*/

const AGGR_TIME = 15 * 60 * 1000

type valueAggregator struct {
	sum   float64
	count float64
}

func (va *valueAggregator) aggregate() uint64 {
	if va.count == 0 {
		return 0
	}
	return uint64(va.sum / va.count)
}

type PerformanceAggregator struct {
	handlers.ReadyMessageStore
	pa            *MobilePerformanceAggregated
	fps           valueAggregator
	cpu           valueAggregator
	memory        valueAggregator
	battery       valueAggregator
	lastTimestamp uint64
}

func (h *PerformanceAggregator) Handle(message Message, messageID uint64, timestamp uint64) Message {
	h.lastTimestamp = timestamp
	if h.pa == nil {
		h.pa = &MobilePerformanceAggregated{} // TODO: struct type in messages
	}
	var event Message = nil
	switch m := message.(type) { // TODO: All Timestamp messages
	case *MobilePerformanceEvent:
		if h.pa.TimestampStart == 0 {
			h.pa.TimestampStart = m.Timestamp
		}
		if h.pa.TimestampStart+AGGR_TIME <= m.Timestamp {
			event = h.Build()
		}
		switch m.Name {
		case "fps":
			h.fps.count += 1
			h.fps.sum += float64(m.Value)
			if m.Value < h.pa.MinFPS || h.pa.MinFPS == 0 {
				h.pa.MinFPS = m.Value
			}
			if m.Value > h.pa.MaxFPS {
				h.pa.MaxFPS = m.Value
			}
		case "mainThreadCPU":
			h.cpu.count += 1
			h.cpu.sum += float64(m.Value)
			if m.Value < h.pa.MinCPU || h.pa.MinCPU == 0 {
				h.pa.MinCPU = m.Value
			}
			if m.Value > h.pa.MaxCPU {
				h.pa.MaxCPU = m.Value
			}
		case "memoryUsage":
			h.memory.count += 1
			h.memory.sum += float64(m.Value)
			if m.Value < h.pa.MinMemory || h.pa.MinMemory == 0 {
				h.pa.MinMemory = m.Value
			}
			if m.Value > h.pa.MaxMemory {
				h.pa.MaxMemory = m.Value
			}
		case "batteryLevel":
			h.battery.count += 1
			h.battery.sum += float64(m.Value)
			if m.Value < h.pa.MinBattery || h.pa.MinBattery == 0 {
				h.pa.MinBattery = m.Value
			}
			if m.Value > h.pa.MaxBattery {
				h.pa.MaxBattery = m.Value
			}
		}
	case *MobileSessionEnd:
		event = h.Build()
	}
	return event
}

func (h *PerformanceAggregator) Build() Message {
	if h.pa == nil {
		return nil
	}

	h.pa.TimestampEnd = h.lastTimestamp
	h.pa.AvgFPS = h.fps.aggregate()
	h.pa.AvgCPU = h.cpu.aggregate()
	h.pa.AvgMemory = h.memory.aggregate()
	h.pa.AvgBattery = h.battery.aggregate()

	event := h.pa

	h.pa = &MobilePerformanceAggregated{}
	for _, agg := range []valueAggregator{h.fps, h.cpu, h.memory, h.battery} {
		agg.sum = 0
		agg.count = 0
	}
	return event
}
