package daemonapi

import (
	"context"
	"fmt"
	"net/http"
	"time"

	"github.com/labstack/echo/v4"

	"github.com/opensvc/om3/v3/daemon/api"
	"github.com/opensvc/om3/v3/daemon/daemonauth"
	"github.com/opensvc/om3/v3/daemon/daemonctx"
	"github.com/opensvc/om3/v3/daemon/daemondata"
	"github.com/opensvc/om3/v3/daemon/daemonenv"
	"github.com/opensvc/om3/v3/daemon/rbac"
	"github.com/opensvc/om3/v3/util/auditstate"
	"github.com/opensvc/om3/v3/util/hostname"
	"github.com/opensvc/om3/v3/util/pubsub"
)

type (
	JWTCreater interface {
		CreateToken(duration time.Duration, xClaims map[string]interface{}) (tk string, expiredAt time.Time, err error)
	}

	DaemonAPI struct {
		AuditRegistry *auditstate.Registry
		Bus           pubsub.Buser
		Daemondata    *daemondata.T
		JWTcreator    JWTCreater

		LabelLocalhost pubsub.Label

		SubQS pubsub.QueueSizer

		localhost string
	}

	contextKey string
)

var (
	contextApiSubQS = contextKey("api-sub-queue-size")

	labelOriginAPI = pubsub.Label{"origin", "api"}
)

func New(ctx context.Context) *DaemonAPI {
	localhost := hostname.Hostname()

	return &DaemonAPI{
		Daemondata:     daemondata.FromContext(ctx),
		AuditRegistry:  daemonctx.AuditRegistry(ctx),
		Bus:            pubsub.BusFromContext(ctx),
		JWTcreator:     daemonauth.JWTCreatorFromContext(ctx),
		LabelLocalhost: pubsub.Label{"node", localhost},
		localhost:      localhost,
		SubQS:          SubQS(ctx),
	}
}

func JSONProblem(ctx echo.Context, code int, title, detail string) error {
	return ctx.JSON(code, api.Problem{
		Detail: detail,
		Title:  title,
		Status: code,
	})
}

func JSONProblemf(ctx echo.Context, code int, title, format string, a ...any) error {
	return ctx.JSON(code, api.Problem{
		Detail: fmt.Sprintf(format, a...),
		Title:  title,
		Status: code,
	})
}

func JSONForbiddenMissingGrant(ctx echo.Context, missing ...rbac.Grant) error {
	return JSONProblemf(ctx, http.StatusForbidden, "Forbidden", "need one of %v grant", missing)
}

func JSONForbiddenMissingRole(ctx echo.Context, missing ...rbac.Role) error {
	return JSONProblemf(ctx, http.StatusForbidden, "Forbidden", "need one of %v role", missing)
}

func JSONForbiddenStrategy(ctx echo.Context, strategy string, expected ...string) error {
	return JSONProblemf(ctx, http.StatusForbidden, "Forbidden", "unexpected strategy %s, need one of %v strategy", strategy, expected)
}

func setStreamHeaders(w http.ResponseWriter) {
	w.Header().Set("Content-Type", "text/event-stream")
	w.Header().Set("Cache-control", "no-store")
	w.Header().Set("Connection", "keep-alive")
	w.Header().Set("Transfer-Encoding", "chunked")
}

// SubQS function returns api pubsub.QueueSizer from context
func SubQS(ctx context.Context) pubsub.QueueSizer {
	subQS, ok := ctx.Value(contextApiSubQS).(pubsub.QueueSizer)
	if ok {
		return subQS
	}
	return pubsub.WithQueueSize(daemonenv.SubQSLarge)
}

// WithSubQS function returns copy of parent with api pubsub.QueueSizer.
func WithSubQS(parent context.Context, subQS pubsub.QueueSizer) context.Context {
	return context.WithValue(parent, contextApiSubQS, subQS)
}
