package clinic_event

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"io"
	"net/http"

	"github.com/pingcap/log"
	"github.com/spf13/viper"
	"go.uber.org/zap"
)

type SeverityLevel int

const (
	Debug    SeverityLevel = -4
	Info     SeverityLevel = 0 // default
	Warning  SeverityLevel = 4
	Critical SeverityLevel = 8

	XActivityHubSource = "x-activityhub-source"
	XActivityHubKey    = "x-activityhub-key"

	EventSource = "user_behavior"
)

var globalEventCli *EventClient

// EventCLient
type EventClient struct {
	client              *http.Client
	activityHubEndpoint string
	sourceKey           string
}

func InitEventClient() {
	if globalEventCli != nil {
		return
	}

	client := &http.Client{}
	globalEventCli = &EventClient{
		client:              client,
		activityHubEndpoint: viper.GetString("clinic.activity_hub_endpoint"),
		sourceKey:           viper.GetString("clinic.source_key"),
	}
}

type EventRequest struct {
	Type            string                 `json:"type"`
	Name            string                 `json:"name"`
	SeverityLevel   int                    `json:"severity"`
	ApplicationID   string                 `json:"application_id"` // tenant id
	ConceptID       string                 `json:"concept_id"`     // project id
	TargetID        string                 `json:"target_id"`      //cluster id
	Catalog         string                 `json:"catalog"`        // event group
	CalibrationTime uint64                 `json:"calibration_time"`
	Author          string                 `json:"author"`
	ContextID       string                 `json:"context_id"`
	Payload         map[string]interface{} `json:"payload"`
}

// SendEvent
func SendEvent(request EventRequest) error {

	if globalEventCli == nil || globalEventCli.activityHubEndpoint == "" {
		return errors.New("global event client is not initialized")
	}
	if request.Type == "" {
		request.Type = "event"
	}

	data, err := json.Marshal(request)
	if err != nil {
		return err
	}
	req, err := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/activity", globalEventCli.activityHubEndpoint), bytes.NewBuffer(data))
	if err != nil {
		log.Error("request failed", zap.Error(err))
		return err
	}

	// add auth header
	req.Header.Add(XActivityHubSource, EventSource)
	req.Header.Add(XActivityHubKey, globalEventCli.sourceKey)

	resp, err := globalEventCli.client.Do(req)
	if err != nil {
		log.Error("send event failed", zap.Error(err))
		return err
	}
	defer func() {
		_ = resp.Body.Close()
	}()

	if resp.StatusCode != http.StatusAccepted {
		bs, err := io.ReadAll(resp.Body)
		log.Error("send event failed",
			zap.String("error msg", string(bs)),
			zap.Error(err),
			zap.String("evnet", request.Name),
			zap.String("tenant-id", request.ApplicationID),
			zap.String("project-id", request.ConceptID),
			zap.String("cluster-id", request.TargetID),
		)
		return fmt.Errorf("send event failed, got status %s", resp.Status)
	}
	return nil
}
