// Copyright 2020-2026 Project Capsule Authors
// SPDX-License-Identifier: Apache-2.0

package admission

import (
	"fmt"
	"strings"

	admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
	"k8s.io/apiserver/pkg/authentication/serviceaccount"

	"github.com/projectcapsule/capsule/pkg/api/rbac"
)

const (
	falseValue string = "false"
)

func BuildGatingUserCondition(opts WebhookOptions, users rbac.UserListSpec, admins rbac.UserListSpec) []admissionregistrationv1.MatchCondition {
	var parts []string

	if opts.CapsuleUsers {
		parts = append(parts, ServiceAccountGroupGuardExpr())
		parts = append(parts, CelUserOrGroupExpr(users))
	}

	if opts.Administrators {
		parts = append(parts, CelUserOrGroupExpr(admins))
	}

	if len(parts) == 0 {
		return nil
	}

	expr := parts[0]
	for i := 1; i < len(parts); i++ {
		expr = fmt.Sprintf("(%s) || (%s)", expr, parts[i])
	}

	return []admissionregistrationv1.MatchCondition{
		{
			Name:       "capsule-user-gate",
			Expression: expr,
		},
	}
}

func ServiceAccountGroupGuardExpr() string {
	return fmt.Sprintf("request.userInfo.groups.exists(g, g == %s)", CelQuote(serviceaccount.AllServiceAccountsGroup))
}

func CelUserOrGroupExpr(l rbac.UserListSpec) string {
	users, groups := l.SplitUsersAndGroups()

	userExpr := falseValue
	if len(users) > 0 {
		userExpr = fmt.Sprintf("request.userInfo.username in %s", CelStringList(users))
	}

	groupExpr := falseValue
	if len(groups) > 0 {
		groupExpr = fmt.Sprintf("request.userInfo.groups.exists(g, g in %s)", CelStringList(groups))
	}

	return fmt.Sprintf("(%s) || (%s)", userExpr, groupExpr)
}

func CelStringList(items []string) string {
	q := make([]string, 0, len(items))
	for _, it := range items {
		q = append(q, CelQuote(it))
	}

	return "[" + strings.Join(q, ",") + "]"
}

func CelQuote(s string) string {
	s = strings.ReplaceAll(s, `\`, `\\`)
	s = strings.ReplaceAll(s, `'`, `\'`)
	s = strings.ReplaceAll(s, "\n", `\n`)
	s = strings.ReplaceAll(s, "\t", `\t`)

	return "'" + s + "'"
}
