package handlers

import (
	"encoding/base64"
	"net/http"
	"strings"

	"github.com/matrix-org/go-neb/clients"
	"github.com/matrix-org/go-neb/database"
	"github.com/matrix-org/go-neb/metrics"
	log "github.com/sirupsen/logrus"
)

// Webhook represents an HTTP handler capable of accepting webhook requests on behalf of services.
type Webhook struct {
	db      *database.ServiceDB
	clients *clients.Clients
}

// NewWebhook returns a new webhook HTTP handler
func NewWebhook(db *database.ServiceDB, cli *clients.Clients) *Webhook {
	return &Webhook{db, cli}
}

// Handle an incoming webhook HTTP request.
//
// The webhook MUST have a known base64 encoded service ID as the last path segment
// in order for this request to be passed to the correct service, or else this will return
// HTTP 400. If the base64 encoded service ID is unknown, this will return HTTP 404.
// Beyond this, the exact response is determined by the specific Service implementation.
func (wh *Webhook) Handle(w http.ResponseWriter, req *http.Request) {
	log.WithField("path", req.URL.Path).Print("Incoming webhook request")
	segments := strings.Split(req.URL.Path, "/")
	// last path segment is the service ID which we will pass the incoming request to,
	// but we've base64d it.
	base64srvID := segments[len(segments)-1]
	bytesSrvID, err := base64.RawURLEncoding.DecodeString(base64srvID)
	if err != nil {
		log.WithError(err).WithField("base64_service_id", base64srvID).Print(
			"Not a b64 encoded string",
		)
		w.WriteHeader(400)
		return
	}
	srvID := string(bytesSrvID)

	service, err := wh.db.LoadService(srvID)
	if err != nil {
		log.WithError(err).WithField("service_id", srvID).Print("Failed to load service")
		w.WriteHeader(404)
		return
	}
	cli, err := wh.clients.Client(service.ServiceUserID())
	if err != nil {
		log.WithError(err).WithField("user_id", service.ServiceUserID()).Print(
			"Failed to retrieve matrix client instance")
		w.WriteHeader(500)
		return
	}
	log.WithFields(log.Fields{
		"service_id":   service.ServiceID(),
		"service_type": service.ServiceType(),
	}).Print("Incoming webhook for service")
	metrics.IncrementWebhook(service.ServiceType())
	service.OnReceiveWebhook(w, req, cli)
}