package web

import (
	"encoding/json"

	. "openreplay/backend/pkg/messages"
	"openreplay/backend/pkg/messages/performance"
)

/*
	Handler name: CpuIssue
	Input events: PerformanceTrack,
				  SetPageLocation
	Output event: IssueEvent
*/

const CpuThreshold = 70 // % out of 100
const CpuMinDurationTrigger = 6 * 1000

type CpuIssueDetector struct {
	startTimestamp uint64
	startMessageID uint64
	lastTimestamp  uint64
	maxRate        uint64
	contextString  string
}

func (f *CpuIssueDetector) createPayload() string {
	p, err := json.Marshal(struct {
		Duration uint64
		Rate     uint64
	}{f.duration(), f.maxRate})
	if err != nil {
		return ""
	}
	return string(p)
}

func (f *CpuIssueDetector) duration() uint64 {
	return f.lastTimestamp - f.startTimestamp
}

func (f *CpuIssueDetector) reset() {
	f.startTimestamp = 0
	f.startMessageID = 0
	f.maxRate = 0
}

func (f *CpuIssueDetector) Build() Message {
	defer f.reset()
	if f.startTimestamp == 0 || f.duration() < CpuMinDurationTrigger {
		return nil
	}
	return &IssueEvent{
		Type:          "cpu",
		Timestamp:     f.startTimestamp,
		MessageID:     f.startMessageID,
		ContextString: f.contextString,
		Payload:       f.createPayload(),
	}
}

func (f *CpuIssueDetector) Handle(message Message, timestamp uint64) Message {
	switch msg := message.(type) {
	case *PerformanceTrack:
		// Ignore if it's a wrong message order
		if timestamp < f.lastTimestamp {
			return nil
		}
		f.lastTimestamp = timestamp
		cpuRate := performance.CPURate(msg.Ticks, performance.TimeDiff(timestamp, f.lastTimestamp))
		// Build event if cpu issue have gone
		if msg.Frames == -1 || msg.Ticks == -1 || cpuRate < CpuThreshold {
			return f.Build()
		}
		// Update values
		if f.startTimestamp == 0 {
			f.startTimestamp = timestamp
			f.startMessageID = message.MsgID()
		}
		if f.maxRate < cpuRate {
			f.maxRate = cpuRate
		}
	case *SetPageLocation:
		f.contextString = msg.URL
	}
	return nil
}
