package api

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

	"iwarma.ru/console/correlator/events"

	log "github.com/sirupsen/logrus"
	"iwarma.ru/console/correlator/rules"
)

// LogUrlMiddleware Write remote address of handler caller
func LogUrlMiddleware(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		cl := log.WithFields(log.Fields{"url": r.URL.String(), "source": "API", "method": r.Method})
		cl.Debugf("Call from %v", r.RemoteAddr)
		next.ServeHTTP(w, r)
	})
}

// ClearStoreHandler Clear rule store
func ClearStoreHandler(store *rules.RuleStore) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		cl := log.WithFields(log.Fields{"url": r.URL, "source": "API", "method": r.Method})
		cl.Trace("Start")
		defer cl.Trace("Finish")

		cl.Info("Clear store")
		store.ClearStore()
		w.WriteHeader(http.StatusOK)
	}
}

// AddRulesHandler Add rules to store
func AddRulesHandler(store *rules.RuleStore) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		cl := log.WithFields(log.Fields{"url": r.URL, "source": "API", "method": r.Method})
		cl.Trace("Start")
		defer cl.Trace("Finish")

		found := false
		if contentType, ok := r.Header["Content-Type"]; ok {

			for _, cur := range contentType {
				if cur == "application/json" {
					found = true
					break
				}
			}

		}

		if !found {
			cl.Errorf("Bad content type")
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		var buffer bytes.Buffer
		tee := io.TeeReader(r.Body, &buffer)

		var newRules []rules.Rule
		err := json.NewDecoder(tee).Decode(&newRules)
		if err != nil {
			cl.Errorf("Can't decode request: %v", err)
			cl.Debugf("Incoming message: %v", buffer.String())
			w.WriteHeader(http.StatusBadRequest)
			return
		}

		cl.Infof("Add new %v rules", len(newRules))
		store.AddRules(newRules...)
		w.WriteHeader(http.StatusOK)
	}
}

// StatHandler Get Correlator and aggregator stat
func StatHandler(agr *events.AggregatedEventStore, cor *rules.RuleStore) func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		cl := log.WithFields(log.Fields{"url": r.URL, "source": "API", "method": r.Method})
		cl.Trace("Start")
		defer cl.Trace("Finish")

		data, err := json.Marshal(struct {
			AggregatorStat *events.Stat `json:"aggregator"`
			CorrelatorStat *rules.Stat  `json:"correlator"`
		}{
			AggregatorStat: agr.GetStat(),
			CorrelatorStat: cor.GetStat(),
		})

		if err != nil {
			cl.Errorf("Can't serialize stat: %v", err)
			w.WriteHeader(http.StatusInternalServerError)
			return
		}

		w.Header().Set("Content-Type", "application/json")
		count, err := w.Write(data)
		if count != len(data) {
			cl.Errorf("Bad write count. Expect %v, got %v", len(data), count)
		}

		if err != nil {
			cl.Errorf("%v", err)
		}
	}
}
