package middleware

import (
	"net/http"

	"haixun-backend/internal/library/authctx"
	app "haixun-backend/internal/library/errors"
	"haixun-backend/internal/library/errors/code"
	"haixun-backend/internal/library/permmatch"
	memberdomain "haixun-backend/internal/model/member/domain/usecase"
	permissiondomain "haixun-backend/internal/model/permission/domain/usecase"
	"haixun-backend/internal/response"
)

// PermissionRBACMiddleware enforces catalog permissions for authenticated members.
// Mount after AuthJWT or MemberAuth so actor is present in context.
type PermissionRBACMiddleware struct {
	members     memberdomain.UseCase
	permissions permissiondomain.UseCase
}

func NewPermissionRBACMiddleware(
	members memberdomain.UseCase,
	permissions permissiondomain.UseCase,
) *PermissionRBACMiddleware {
	return &PermissionRBACMiddleware{members: members, permissions: permissions}
}

func (m *PermissionRBACMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		actor, ok := authctx.ActorFromContext(r.Context())
		if !ok {
			response.Write(r.Context(), w, nil, app.For(code.Auth).AuthUnauthorized("missing actor"))
			return
		}
		if m.members == nil || m.permissions == nil {
			response.Write(r.Context(), w, nil, app.For(code.Permission).SysNotImplemented("permission rbac is not configured"))
			return
		}

		member, err := m.members.GetByUID(r.Context(), actor.TenantID, actor.UID)
		if err != nil {
			response.Write(r.Context(), w, nil, err)
			return
		}

		me, err := m.permissions.Me(r.Context(), member, false)
		if err != nil {
			response.Write(r.Context(), w, nil, err)
			return
		}
		if !permmatch.RequestAllowed(me.Permissions, r.Method, r.URL.Path) {
			response.Write(r.Context(), w, nil, app.For(code.Permission).AuthForbidden("permission denied"))
			return
		}

		next(w, r)
	}
}
