package middleware

import (
	"context"
	"net/http"
	"strings"

	"cmr-backend/internal/apperr"
	"cmr-backend/internal/httpx"
	"cmr-backend/internal/platform/jwtx"
)

type opsAuthContextKey string

const opsAuthKey opsAuthContextKey = "ops-auth"

type OpsAuthContext struct {
	OpsUserID       string
	OpsUserPublicID string
	RoleCode        string
}

func NewOpsAuthMiddleware(jwtManager *jwtx.Manager, appEnv string) func(http.Handler) http.Handler {
	devContext := func(r *http.Request) *http.Request {
		ctx := context.WithValue(r.Context(), opsAuthKey, &OpsAuthContext{
			OpsUserID:       "dev-ops-user",
			OpsUserPublicID: "ops_dev_console",
			RoleCode:        "owner",
		})
		return r.WithContext(ctx)
	}

	return func(next http.Handler) http.Handler {
		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			authHeader := strings.TrimSpace(r.Header.Get("Authorization"))
			if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") {
				if appEnv != "production" {
					next.ServeHTTP(w, devContext(r))
					return
				}
				httpx.WriteError(w, apperr.New(http.StatusUnauthorized, "unauthorized", "missing bearer token"))
				return
			}

			token := strings.TrimSpace(strings.TrimPrefix(authHeader, "Bearer "))
			claims, err := jwtManager.ParseAccessToken(token)
			if err != nil {
				if appEnv != "production" {
					next.ServeHTTP(w, devContext(r))
					return
				}
				httpx.WriteError(w, apperr.New(http.StatusUnauthorized, "invalid_token", "invalid access token"))
				return
			}
			if claims.ActorType != "ops" {
				if appEnv != "production" {
					next.ServeHTTP(w, devContext(r))
					return
				}
				httpx.WriteError(w, apperr.New(http.StatusUnauthorized, "invalid_token", "invalid ops access token"))
				return
			}

			ctx := context.WithValue(r.Context(), opsAuthKey, &OpsAuthContext{
				OpsUserID:       claims.UserID,
				OpsUserPublicID: claims.UserPublicID,
				RoleCode:        claims.RoleCode,
			})
			next.ServeHTTP(w, r.WithContext(ctx))
		})
	}
}

func GetOpsAuthContext(ctx context.Context) *OpsAuthContext {
	auth, _ := ctx.Value(opsAuthKey).(*OpsAuthContext)
	return auth
}
