package azure

import (
	"context"
	"crypto/rand"
	"fmt"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/authorization/armauthorization"
	"github.com/pkg/errors"
)

// RoleManager Azure角色管理器
type RoleManager struct {
	client         *armauthorization.RoleAssignmentsClient
	subscriptionID string
	config         *Config
}

// RoleAssignment 角色分配信息
type RoleAssignment struct {
	PrincipalID    string // 用户、组或服务主体的 Object ID
	RoleDefinition string // 角色定义 ID 或名称
	Scope          string // 分配范围
}

// NewRoleManager 创建角色管理器
func NewRoleManager(subscriptionID string, config *Config) (*RoleManager, error) {

	cred, err := config.createCredential()
	if err != nil {
		return nil, errors.Wrap(err, "failed to create Azure credentials")
	}

	client, err := armauthorization.NewRoleAssignmentsClient(subscriptionID, cred, nil)
	if err != nil {
		return nil, errors.Wrap(err, "failed to create role assignments client")
	}

	return &RoleManager{
		client:         client,
		subscriptionID: subscriptionID,
		config:         config,
	}, nil
}

// createCredential 创建凭据
func (c *Config) createCredential() (azcore.TokenCredential, error) {
	return azidentity.NewClientSecretCredential(
		c.TenantID,
		c.ClientID,
		c.ClientSecret,
		nil,
	)
}

// AssignSubscriptionRole 给用户在订阅级别分配角色
func (rm *RoleManager) AssignSubscriptionRole(ctx context.Context, assignment RoleAssignment) (*armauthorization.RoleAssignment, error) {
	if assignment.PrincipalID == "" {
		return nil, errors.New("principal ID cannot be empty")
	}
	if assignment.RoleDefinition == "" {
		return nil, errors.New("role definition ID cannot be empty")
	}

	// 设置作用域为订阅级别
	scope := fmt.Sprintf("/subscriptions/%s", rm.subscriptionID)
	if assignment.Scope != "" {
		scope = assignment.Scope
	}

	// 生成唯一的分配 ID
	assignmentName := generateUniqueID()

	// 创建角色分配参数
	params := armauthorization.RoleAssignmentCreateParameters{
		Properties: &armauthorization.RoleAssignmentProperties{
			PrincipalID:      to.Ptr(assignment.PrincipalID),
			RoleDefinitionID: to.Ptr(assignment.RoleDefinition),
		},
	}

	// 执行角色分配
	result, err := rm.client.Create(ctx, scope, assignmentName, params, nil)
	if err != nil {
		return nil, errors.Wrap(err, "failed to create role assignment")
	}

	return &result.RoleAssignment, nil
}

// GetUserRoleAssignments 获取用户的角色分配
func (rm *RoleManager) GetUserRoleAssignments(ctx context.Context, principalID string) ([]*armauthorization.RoleAssignment, error) {
	if principalID == "" {
		return nil, errors.New("principal ID cannot be empty")
	}

	scope := fmt.Sprintf("/subscriptions/%s", rm.subscriptionID)
	filter := fmt.Sprintf("principalId eq '%s'", principalID)

	var assignments []*armauthorization.RoleAssignment
	pager := rm.client.NewListForScopePager(scope, &armauthorization.RoleAssignmentsClientListForScopeOptions{
		Filter: to.Ptr(filter),
	})

	for pager.More() {
		page, err := pager.NextPage(ctx)
		if err != nil {
			return nil, errors.Wrap(err, "failed to get role assignments page")
		}

		for _, assignment := range page.Value {
			assignments = append(assignments, assignment)
		}
	}

	return assignments, nil
}

// RemoveSubscriptionRole 移除用户的订阅角色
func (rm *RoleManager) RemoveSubscriptionRole(ctx context.Context, roleAssignmentID string) error {
	if roleAssignmentID == "" {
		return errors.New("role assignment ID cannot be empty")
	}

	_, err := rm.client.DeleteByID(ctx, roleAssignmentID, nil)
	if err != nil {
		return errors.Wrap(err, "failed to delete role assignment")
	}

	return nil
}

// generateUniqueID 生成唯一的分配 ID
func generateUniqueID() string {
	b := make([]byte, 16)
	_, err := rand.Read(b)
	if err != nil {
		panic(err)
	}
	return fmt.Sprintf("%x-%x-%x-%x-%x", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
}

// 常用的 Azure 内置角色定义 ID
const (
	// 订阅级别常用角色
	RoleOwner               = "/subscriptions/{subscription-id}/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635"
	RoleContributor         = "/subscriptions/{subscription-id}/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c"
	RoleReader              = "/subscriptions/{subscription-id}/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7"
	RoleUserAccessAdmin     = "/subscriptions/{subscription-id}/providers/Microsoft.Authorization/roleDefinitions/18d7d88d-d35e-4fb5-a5c3-7773c20a72d9"
	RoleReaderAndDataAccess = "/subscriptions/{subscription-id}/providers/Microsoft.Authorization/roleDefinitions/c12c1c16-33a1-487b-954d-41c89c60f349"
)

// GetBuiltInRoleDefinitionID 获取内置角色定义 ID
func (rm *RoleManager) GetBuiltInRoleDefinitionID(roleName string) string {
	subscriptionID := rm.subscriptionID

	switch roleName {
	case "Owner":
		return fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Authorization/roleDefinitions/8e3af657-a8ff-443c-a75c-2fe8c4bcb635", subscriptionID)
	case "Contributor":
		return fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c", subscriptionID)
	case "Reader":
		return fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Authorization/roleDefinitions/acdd72a7-3385-48ef-bd42-f606fba81ae7", subscriptionID)
	case "User Access Administrator":
		return fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Authorization/roleDefinitions/18d7d88d-d35e-4fb5-a5c3-7773c20a72d9", subscriptionID)
	case "Reader and Data Access":
		return fmt.Sprintf("/subscriptions/%s/providers/Microsoft.Authorization/roleDefinitions/c12c1c16-33a1-487b-954d-41c89c60f349", subscriptionID)
	default:
		return roleName // 如果不是内置角色名称，假设它已经是完整的角色定义 ID
	}
}
