package permissionsimp

import (
	"context"
	"net/http"

	"github.com/tech/sendico/pkg/api/http/response"
	"github.com/tech/sendico/pkg/model"
	"github.com/tech/sendico/pkg/mutil/mzap"
	"github.com/tech/sendico/server/interface/api/sresponse"
	mutil "github.com/tech/sendico/server/internal/mutil/param"
	"go.mongodb.org/mongo-driver/v2/bson"
	"go.uber.org/zap"
)

func (a *PermissionsAPI) getRolePolicies(ctx context.Context, roles []model.RoleDescription) ([]model.RolePolicy, error) {
	policies := make([]model.RolePolicy, 0)

	uniqueRefs := make(map[bson.ObjectID]struct{})
	for _, role := range roles {
		uniqueRefs[*role.GetID()] = struct{}{}
	}

	for ref := range uniqueRefs {
		plcs, err := a.auth.Permission().GetPolicies(ctx, ref)
		if err != nil {
			a.logger.Warn("Failed to fetch role permissions", zap.Error(err), mzap.ObjRef("role_ref", ref))
			return nil, err
		}
		policies = append(policies, plcs...)
	}
	return policies, nil
}

func (a *PermissionsAPI) getAll(r *http.Request, account *model.Account, accessToken *sresponse.TokenData) http.HandlerFunc {
	orgRef, err := mutil.GetOrganizationRef(r)
	if err != nil {
		a.logger.Warn("Failed to restore organization reference", zap.Error(err), zap.String("organization_ref", mutil.GetOrganizationID(r)))
		return response.BadReference(a.logger, a.Name(), mutil.ObjRefName(), mutil.GetOrganizationID(r), err)
	}

	ctx := r.Context()
	res, err := a.enforcer.Enforce(ctx, a.rolesPermissionRef, account.ID, orgRef, bson.NilObjectID, model.ActionRead)
	if err != nil {
		a.logger.Debug("Error occurred", zap.Error(err))
		response.Auto(a.logger, a.Name(), err)
	}
	if !res {
		a.logger.Debug("Access to permissions denied")
		response.AccessDenied(a.logger, a.Name(), "no required permissiosn to read account permissions data")
	}

	var org model.Organization
	if err := a.db.Get(ctx, account.ID, orgRef, &org); err != nil {
		a.logger.Warn("Failed to fetch venue", zap.Error(err), mzap.ObjRef("organization_ref", orgRef))
		return response.Auto(a.logger, a.Name(), err)
	}
	roles := make([]model.Role, 0)
	permissions := make([]model.Permission, 0)
	for _, employee := range org.Members {
		rls, prms, err := a.enforcer.GetPermissions(ctx, employee, orgRef)
		if len(rls) == 0 {
			a.logger.Warn("No roles defined for account", mzap.ObjRef("employee_ref", employee), mzap.ObjRef("organization_ref", orgRef))
			return response.NotFound(a.logger, a.Name(), "User has no roles assigned")
		}
		if err != nil {
			a.logger.Warn("Failed to fetch account policies", zap.Error(err), mzap.ObjRef("organization_ref", orgRef))
			return response.Auto(a.logger, a.Name(), err)
		}
		roles = append(roles, rls...)
		permissions = append(permissions, prms...)
	}

	return a.permissions(ctx, orgRef, roles, permissions, accessToken)
}
