package custom

import (
	"encoding/json"
	"fmt"
	. "openreplay/backend/pkg/messages"
)

const PageEventTimeout = 1 * 60 * 1000

type pageEventBuilder struct {
	pageEvent          *PageEvent
	firstTimingHandled bool
	webVitals          map[string]string
}

func NewPageEventBuilder() *pageEventBuilder {
	ieBuilder := &pageEventBuilder{}
	return ieBuilder
}

func (b *pageEventBuilder) Handle(message Message, timestamp uint64) Message {
	switch msg := message.(type) {
	case *SetPageLocation:
		if msg.NavigationStart == 0 { // routing without new page loading
			return &PageEvent{
				URL:       msg.URL,
				Referrer:  msg.Referrer,
				Loaded:    false,
				MessageID: message.MsgID(),
				Timestamp: timestamp,
			}
		} else {
			pageEvent := b.Build()
			b.pageEvent = &PageEvent{
				URL:       msg.URL,
				Referrer:  msg.Referrer,
				Loaded:    true,
				MessageID: message.MsgID(),
				Timestamp: timestamp,
			}
			return pageEvent
		}
	case *PageLoadTiming:
		if b.pageEvent == nil {
			break
		}
		if msg.RequestStart <= 30000 {
			b.pageEvent.RequestStart = msg.RequestStart
		}
		if msg.ResponseStart <= 30000 {
			b.pageEvent.ResponseStart = msg.ResponseStart
		}
		if msg.ResponseEnd <= 30000 {
			b.pageEvent.ResponseEnd = msg.ResponseEnd
		}
		if msg.DomContentLoadedEventStart <= 30000 {
			b.pageEvent.DomContentLoadedEventStart = msg.DomContentLoadedEventStart
		}
		if msg.DomContentLoadedEventEnd <= 30000 {
			b.pageEvent.DomContentLoadedEventEnd = msg.DomContentLoadedEventEnd
		}
		if msg.LoadEventStart <= 30000 {
			b.pageEvent.LoadEventStart = msg.LoadEventStart
		}
		if msg.LoadEventEnd <= 30000 {
			b.pageEvent.LoadEventEnd = msg.LoadEventEnd
		}
		if msg.FirstPaint <= 30000 {
			b.pageEvent.FirstPaint = msg.FirstPaint
		}
		if msg.FirstContentfulPaint <= 30000 {
			b.pageEvent.FirstContentfulPaint = msg.FirstContentfulPaint
		}
		return nil
	case *PageRenderTiming:
		if b.pageEvent == nil {
			break
		}
		b.pageEvent.SpeedIndex = msg.SpeedIndex
		b.pageEvent.VisuallyComplete = msg.VisuallyComplete
		b.pageEvent.TimeToInteractive = msg.TimeToInteractive
		return nil
	case *WebVitals:
		if b.webVitals == nil {
			b.webVitals = make(map[string]string)
		}
		b.webVitals[msg.Name] = msg.Value
	}

	if b.pageEvent != nil && b.pageEvent.Timestamp+PageEventTimeout < timestamp {
		return b.Build()
	}
	return nil
}

func (b *pageEventBuilder) Build() Message {
	if b.pageEvent == nil {
		return nil
	}
	pageEvent := b.pageEvent
	b.pageEvent = nil
	b.firstTimingHandled = false
	if b.webVitals != nil {
		if vitals, err := json.Marshal(b.webVitals); err == nil {
			pageEvent.WebVitals = string(vitals)
		} else {
			fmt.Printf("Error marshalling web vitals: %v\n", err)
		}
	}
	return pageEvent
}
