{# The final Go code is autogenerated, but this template is not. Please file bugs! #}
package glean

// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

// AUTOGENERATED BY glean_parser v{{ parser_version }}. DO NOT EDIT.

// required imports
import (
	"encoding/json"
    "fmt"
	"strconv"
	"time"

	"github.com/google/uuid"
)

// log type string used to identify logs to process in the Moz Data Pipeline
var gleanEventMozlogType string = "glean-server-event"

type GleanEventsLogger struct {
	AppID             string // Application Id to identify application per Glean standards
	AppDisplayVersion string // Version of application emitting the event
	AppChannel        string // Channel to differentiate logs from prod/beta/staging/devel
}

// exported type for public method parameters
type RequestInfo struct {
	UserAgent string
	IpAddress string
}

// default empty values will be omitted in json from ping struct definition
var defaultRequestInfo = RequestInfo{
	UserAgent: "",
	IpAddress: "",
}

// structs to construct the glean ping
type clientInfo struct {
	TelemetrySDKBuild string `json:"telemetry_sdk_build"`
	FirstRunDate      string `json:"first_run_date"`
	OS                string `json:"os"`
	OSVersion         string `json:"os_version"`
	Architecture      string `json:"architecture"`
	AppBuild          string `json:"app_build"`
	AppDisplayVersion string `json:"app_display_version"`
	AppChannel        string `json:"app_channel"`
}

type pingInfo struct {
	Seq       int    `json:"seq"`
	StartTime string `json:"start_time"`
	EndTime   string `json:"end_time"`
}

type ping struct {
	DocumentNamespace string `json:"document_namespace"`
	DocumentType      string `json:"document_type"`
	DocumentVersion   string `json:"document_version"`
	DocumentID        string `json:"document_id"`
	UserAgent         string `json:"user_agent,omitempty"`
	IpAddress         string `json:"ip_address,omitempty"`
	Payload           string `json:"payload"`
}

type metrics map[string]map[string]interface{}

type pingPayload struct {
	ClientInfo clientInfo   `json:"client_info"`
	PingInfo   pingInfo     `json:"ping_info"`
	Metrics    metrics      `json:"metrics"`
	Events     []gleanEvent `json:"events"`
}

type gleanEvent struct {
	Category  string            `json:"category"`
	Name      string            `json:"name"`
	Timestamp int64             `json:"timestamp"`
	Extra     map[string]string `json:"extra"`
}

type logEnvelope struct {
	Timestamp string
	Logger    string
	Type      string
	Fields    ping
}

func (g GleanEventsLogger) createClientInfo() clientInfo {
	// Fields with default values are required in the Glean schema, but not used in server context
	return clientInfo{
		TelemetrySDKBuild: "glean_parser v{{ parser_version }}",
		FirstRunDate:      "Unknown",
		OS:                "Unknown",
		OSVersion:         "Unknown",
		Architecture:      "Unknown",
		AppBuild:          "Unknown",
		AppDisplayVersion: g.AppDisplayVersion,
		AppChannel:        g.AppChannel,
	}
}

func createPingInfo() pingInfo {
	{# times are ISO-8601 strings, e.g. "2023-12-19T22:09:17.440Z" #}
	var now = time.Now().UTC().Format("2006-01-02T15:04:05.000Z")
	return pingInfo{
		Seq:       0,
		StartTime: now,
		EndTime:   now,
	}
}

func (g GleanEventsLogger) createPing(documentType string, config RequestInfo, payload pingPayload) ping {
	var payloadJson, payloadErr = json.Marshal(payload)
	if payloadErr != nil {
		panic("Unable to marshal payload to json")
	}
	var documentId = uuid.New()
	return ping{
		DocumentNamespace: g.AppID,
		DocumentType:      documentType,
		DocumentVersion:   "1",
		DocumentID:        documentId.String(),
		UserAgent:         config.UserAgent,
		IpAddress:         config.IpAddress,
		Payload:           string(payloadJson),
	}
}

// method called by each event method.
// construct the ping, wrap it in the envelope, and print to stdout
func (g GleanEventsLogger) record(
	documentType string,
	requestInfo RequestInfo,
	metrics metrics,
	events []gleanEvent,
) {
	var telemetryPayload = pingPayload{
		ClientInfo: g.createClientInfo(),
		PingInfo:   createPingInfo(),
		Metrics:    metrics,
		Events:     events,
	}

	var ping = g.createPing(documentType, requestInfo, telemetryPayload)

	var envelope = logEnvelope{
		Timestamp: strconv.FormatInt(time.Now().UnixNano(), 10),
		Logger:    "glean",
		Type:      gleanEventMozlogType,
		Fields:    ping,
	}
	var envelopeJson, envelopeErr = json.Marshal(envelope)
	if envelopeErr != nil {
		panic("Unable to marshal log envelope to json")
	}
	fmt.Println(string(envelopeJson))
}

{% for event in events_ping["event"] %}
type {{ event|event_type_name }} struct {
  {% for metric_type, metrics in events_ping.items() %}
  {% if metric_type != 'event' %}
  {% for metric in metrics %}
  {{ metric|metric_argument_name }} {{ metric.type|go_metric_type }} // {{ metric.description|clean_string }}
  {% endfor %}
  {% endif %}
  {% endfor %}
  {% for extra, metadata in event.extra_keys.items() %}
  {{ extra|event_extra_name }} {{ metadata.type|go_metric_type }} // {{ metadata.description|clean_string }}
  {% endfor %}
}

// Record and submit an {{ event|event_type_name }} event.
// {{ event.description|clean_string }}
func (g GleanEventsLogger) Record{{ event|event_type_name }}(
	requestInfo RequestInfo,
	params {{ event|event_type_name }},
) {
	var metrics = metrics{
    {% for metric_type, metrics in events_ping.items() %}
		{% if metric_type != 'event' %}
		"{{ metric_type }}": {
		{% for metric in metrics %}
            {% if metric_type =='datetime' %}
			"{{ metric|metric_name }}": params.{{ metric|metric_argument_name }}.Format("2006-01-02T15:04:05.000Z"),
            {%  else %}
            "{{ metric|metric_name }}": params.{{ metric|metric_argument_name }},
            {% endif %}
		{% endfor %}
		},
		{% endif %}
    {% endfor %}
	}
	var extraKeys = map[string]string{
    {% for extra, metadata in event.extra_keys.items() %}
		{# convert all extra fields to string for submission #}
		{% if metadata.type == 'boolean' %}
		"{{ extra }}": fmt.Sprintf("%t", params.{{ extra|event_extra_name }}),
		{% elif metadata.type == 'quantity' %}
		"{{ extra }}": fmt.Sprintf("%d", params.{{ extra|event_extra_name }}),
		{% else %}
		"{{ extra }}": params.{{ extra|event_extra_name }},
		{% endif %}
    {% endfor %}
	}
	var events = []gleanEvent{
		gleanEvent{
			Category:  "{{ event.category }}",
			Name:      "{{ event.name }}",
			Timestamp: time.Now().UnixMilli(),
			Extra:     extraKeys,
		},
	}
	g.record("events", requestInfo, metrics, events)
}

// Record and submit an {{ event|event_type_name }} event omitting user request info
// {{ event.description|clean_string }}
func (g GleanEventsLogger) Record{{ event|event_type_name }}WithoutUserInfo(
  params {{ event|event_type_name }},
) {
	g.Record{{ event|event_type_name }}(defaultRequestInfo, params)
}

{% endfor %}
