package logparse

import (
	"bytes"
	"encoding/json"
	"sync"
)

type logType string

// logtypes
const (
	logTypeBackendServiceCallSuccess logType = "backend_service_call_success"
	logTypeBackendServiceCallError   logType = "backend_service_call_error"
	logTypeAdminPanelRequest         logType = "admin_panel_request"
)

var (
	logTypes = map[logType]interface{}{
		logTypeBackendServiceCallSuccess: nil,
		logTypeBackendServiceCallError:   nil,
		logTypeAdminPanelRequest:         nil,
	}
)

// LogLine is a single log line parsed
type LogLine struct {
	Message []byte

	initSync sync.Once
	logType  logType
	message  []byte
}

func (l *LogLine) init() {
	l.initSync.Do(func() {
		l.message = l.stripMessage()
		l.parseType()
	})
}

// loglines can start with junk. strip until we find a open bracket
func (l *LogLine) stripMessage() []byte {
	if start := bytes.Index(l.Message, []byte("{")); start >= 0 {
		return l.Message[start:]
	}
	return nil
}

func (l *LogLine) parseType() {
	parsed := struct {
		Type logType `json:"_type"`
	}{}

	if err := json.Unmarshal(l.message, &parsed); err != nil {
		return
	}

	if _, ok := logTypes[parsed.Type]; !ok {
		return
	}

	l.logType = parsed.Type
}

// APEndpointCall ...
func (l *LogLine) APEndpointCall() (*AdminPanelRequest, bool) {
	l.init()
	if l.logType == logTypeAdminPanelRequest {
		m := new(AdminPanelRequest)
		if err := json.Unmarshal(l.message, m); err != nil {
			return nil, false
		}

		return m, true
	}

	return nil, false
}

// BackendServiceCallSuccess ...
func (l *LogLine) BackendServiceCallSuccess() (*BackendServiceCallSuccess, bool) {
	l.init()

	if l.logType == logTypeBackendServiceCallSuccess {
		m := new(BackendServiceCallSuccess)
		if err := json.Unmarshal(l.message, m); err != nil {
			return nil, false
		}

		return m, true
	}

	return nil, false
}

// BackendServiceCallError ...
func (l *LogLine) BackendServiceCallError() (*BackendServiceCallError, bool) {
	l.init()

	if l.logType == logTypeBackendServiceCallError {
		m := new(BackendServiceCallError)
		if err := json.Unmarshal(l.message, m); err != nil {
			return nil, false
		}

		return m, true
	}

	return nil, false
}
