package admin

import (
	"context"
	"errors"
	"fmt"
	"strings"

	platformusers "github.com/ultisuite/ulti-backend/internal/users"
)

type bulkUsersRequest struct {
	UserIDs  []string `json:"user_ids"`
	Action   string   `json:"action"`
	Role     string   `json:"role"`
	GroupID  string   `json:"group_id"`
}

type bulkUsersResult struct {
	SuccessCount int                 `json:"success_count"`
	Failed       []bulkUserFailure   `json:"failed,omitempty"`
}

type bulkUserFailure struct {
	UserID  string `json:"user_id"`
	Message string `json:"message"`
}

func (s *Service) BulkUsersAction(ctx context.Context, actorSub string, req bulkUsersRequest) (bulkUsersResult, error) {
	action := strings.ToLower(strings.TrimSpace(req.Action))
	userIDs := dedupeNonEmpty(req.UserIDs)
	if len(userIDs) == 0 {
		return bulkUsersResult{}, fmt.Errorf("no user ids")
	}

	result := bulkUsersResult{}
	switch action {
	case "disable":
		for _, userID := range userIDs {
			if err := s.DisableUser(ctx, actorSub, userID); err != nil {
				result.Failed = append(result.Failed, bulkUserFailure{UserID: userID, Message: bulkErrorMessage(err)})
				continue
			}
			result.SuccessCount++
		}
	case "reactivate":
		for _, userID := range userIDs {
			if err := s.ReactivateUser(ctx, actorSub, userID); err != nil {
				result.Failed = append(result.Failed, bulkUserFailure{UserID: userID, Message: bulkErrorMessage(err)})
				continue
			}
			result.SuccessCount++
		}
	case "delete":
		for _, userID := range userIDs {
			if err := s.DeleteUser(ctx, actorSub, userID); err != nil {
				result.Failed = append(result.Failed, bulkUserFailure{UserID: userID, Message: bulkErrorMessage(err)})
				continue
			}
			result.SuccessCount++
		}
	case "set_role":
		role := strings.TrimSpace(req.Role)
		for _, userID := range userIDs {
			if _, err := s.SetUserRole(ctx, actorSub, userID, role); err != nil {
				result.Failed = append(result.Failed, bulkUserFailure{UserID: userID, Message: bulkErrorMessage(err)})
				continue
			}
			result.SuccessCount++
		}
	case "add_to_group":
		groupID := strings.TrimSpace(req.GroupID)
		if groupID == "" {
			return bulkUsersResult{}, fmt.Errorf("group_id required")
		}
		if err := s.AddUsersToGroup(ctx, actorSub, groupID, userIDs); err != nil {
			return bulkUsersResult{}, err
		}
		result.SuccessCount = len(userIDs)
	case "remove_from_group":
		groupID := strings.TrimSpace(req.GroupID)
		if groupID == "" {
			return bulkUsersResult{}, fmt.Errorf("group_id required")
		}
		if err := s.RemoveUsersFromGroup(ctx, actorSub, groupID, userIDs); err != nil {
			return bulkUsersResult{}, err
		}
		result.SuccessCount = len(userIDs)
	default:
		return bulkUsersResult{}, fmt.Errorf("invalid action")
	}

	s.logAudit(ctx, actorSub, "bulk_users_action", map[string]any{
		"action":        action,
		"success_count": result.SuccessCount,
		"failed_count":  len(result.Failed),
		"group_id":      strings.TrimSpace(req.GroupID),
		"role":          strings.TrimSpace(req.Role),
	})
	return result, nil
}

func bulkErrorMessage(err error) string {
	if errors.Is(err, ErrNotFound) {
		return "not found"
	}
	if errors.Is(err, platformusers.ErrLastPlatformAdmin) {
		return "cannot remove the last platform admin"
	}
	if err == nil {
		return ""
	}
	return err.Error()
}

func dedupeNonEmpty(ids []string) []string {
	seen := make(map[string]struct{}, len(ids))
	out := make([]string, 0, len(ids))
	for _, id := range ids {
		id = strings.TrimSpace(id)
		if id == "" {
			continue
		}
		if _, ok := seen[id]; ok {
			continue
		}
		seen[id] = struct{}{}
		out = append(out, id)
	}
	return out
}
