package azure

import (
	"context"
	"fmt"
	"strings"

	"github.com/Azure/azure-sdk-for-go/sdk/azcore"
	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
	"github.com/spf13/viper"

	"github.com/pingcap-inc/pchub/internal/apiserver/store"
	modelv1 "github.com/pingcap-inc/pchub/model/v1"
	"github.com/pingcap-inc/pchub/pkg/errors"
	"github.com/pingcap-inc/pchub/pkg/log"
)

// Provider Azure云平台提供者
type Provider struct {
	config *Config
	store  store.Factory
}

// Config Azure配置
type Config struct {
	ClientID     string `mapstructure:"client_id"`
	ClientSecret string `mapstructure:"client_secret"`
	TenantID     string `mapstructure:"tenant_id"`
}

// NewProvider 创建Azure提供者
func NewProvider() (*Provider, error) {
	return NewProviderWithStore(nil)
}

// NewProviderWithStore 创建带有store的Azure提供者
func NewProviderWithStore(storeFactory store.Factory) (*Provider, error) {
	config := &Config{}

	// 从配置中读取Azure凭据
	if err := viper.UnmarshalKey("azure", config); err != nil {
		return nil, fmt.Errorf("failed to unmarshal Azure config: %w", err)
	}

	// 验证配置
	if err := config.Validate(); err != nil {
		return nil, fmt.Errorf("invalid Azure config: %w", err)
	}

	return &Provider{
		config: config,
		store:  storeFactory,
	}, nil
}

// ValidateConfig 验证配置
func (c *Config) Validate() error {
	if c.ClientID == "" {
		return errors.New("Azure client_id is required")
	}
	if c.ClientSecret == "" {
		return errors.New("Azure client_secret is required")
	}
	if c.TenantID == "" {
		return errors.New("Azure tenant_id is required")
	}
	return nil
}

// GetProviderName 获取平台名称
func (p *Provider) GetProviderName() string {
	return "Azure"
}

// ValidateConfig 验证配置
func (p *Provider) ValidateConfig() error {
	return p.config.Validate()
}

// getRoleManager 获取或创建角色管理器
func (p *Provider) getRoleManager(subscriptionID string) (*RoleManager, error) {
	return NewRoleManager(subscriptionID, p.config)
}

// SyncUserRoles 同步用户角色
func (p *Provider) SyncUserRoles(ctx context.Context, roles []*modelv1.RoleMembers, cloudResource *modelv1.CloudResource, optionType int) error {
	subscriptionID := cloudResource.CloudInsID
	log.L(ctx).Infof("Starting Azure role sync for subscription: %s", subscriptionID)

	// 验证角色
	if err := p.validateRoles(roles); err != nil {
		return err
	}

	switch optionType {
	case modelv1.Add:
		return p.addUserRoles(ctx, roles, subscriptionID)
	case modelv1.Delete:
		return p.deleteUserRoles(ctx, roles, subscriptionID)
	case modelv1.DeleteAll:
		return p.deleteAllUserRoles(ctx, roles, subscriptionID)
	default:
		return errors.New("unknown option type")
	}
}

// validateRoles 验证角色
func (p *Provider) validateRoles(roles []*modelv1.RoleMembers) error {
	if len(roles) == 0 {
		return errors.New("role is empty")
	}

	for _, role := range roles {
		if role.Role == nil {
			continue
		}
		if _, ok := modelv1.AzureRoleGUIDs[role.Role.NameInProvider]; !ok {
			return fmt.Errorf("role %s is not allowed in Azure", role.Role.NameInProvider)
		}
	}
	return nil
}

// addUserRoles 添加用户角色
func (p *Provider) addUserRoles(ctx context.Context, roles []*modelv1.RoleMembers, subscriptionID string) error {
	for _, role := range roles {
		if err := p.addRoleToMembers(ctx, role, subscriptionID); err != nil {
			log.L(ctx).Warnf("Failed to add role %s: %v", role.Role.Name, err)
		}
	}
	return nil
}

// addRoleToMembers 为成员添加角色
func (p *Provider) addRoleToMembers(ctx context.Context, role *modelv1.RoleMembers, subscriptionID string) error {
	// 获取用户Object IDs
	emails := p.extractEmails(role.Members)
	userObjectIDs, err := GetAzureUserObjectIDs(ctx, emails, p.config.TenantID, p.config.ClientID, p.config.ClientSecret)
	if err != nil {
		return fmt.Errorf("failed to get Azure Object IDs: %w", err)
	}

	// 为每个成员分配角色
	for _, member := range role.Members {
		objectID, exists := userObjectIDs[member.Email]
		if !exists {
			log.L(ctx).Warnf("Azure Object ID not found for user %s", member.Email)
			continue
		}

		if err := p.assignRoleToUser(ctx, objectID, role.Role.NameInProvider, subscriptionID); err != nil {
			log.L(ctx).Warnf("Failed to assign role to user %s: %v", member.Email, err)
		} else {
			log.L(ctx).Infof("Successfully assigned role %s to user %s", role.Role.Name, member.Email)
		}
	}
	return nil
}

// assignRoleToUser 为用户分配角色
func (p *Provider) assignRoleToUser(ctx context.Context, objectID, roleGUID, subscriptionID string) error {
	roleManager, err := p.getRoleManager(subscriptionID)
	if err != nil {
		return fmt.Errorf("failed to create role manager: %w", err)
	}

	fullRoleDefinition := BuildAzureRoleDefinitionPath(subscriptionID, roleGUID)

	assignment := RoleAssignment{
		PrincipalID:    objectID,
		RoleDefinition: fullRoleDefinition,
	}

	_, err = roleManager.AssignSubscriptionRole(ctx, assignment)
	return err
}

// deleteUserRoles 删除用户角色
func (p *Provider) deleteUserRoles(ctx context.Context, roles []*modelv1.RoleMembers, subscriptionID string) error {
	for _, role := range roles {
		if err := p.deleteRoleFromMembers(ctx, role, subscriptionID); err != nil {
			log.L(ctx).Warnf("Failed to delete role %s: %v", role.Role.Name, err)
		}
	}
	return nil
}

// deleteRoleFromMembers 从成员删除角色
func (p *Provider) deleteRoleFromMembers(ctx context.Context, role *modelv1.RoleMembers, subscriptionID string) error {
	// 获取用户Object IDs
	emails := p.extractEmails(role.Members)
	userObjectIDs, err := GetAzureUserObjectIDs(ctx, emails, p.config.TenantID, p.config.ClientID, p.config.ClientSecret)
	if err != nil {
		return fmt.Errorf("failed to get Azure Object IDs: %w", err)
	}

	// 为每个成员删除角色
	for _, member := range role.Members {
		objectID, exists := userObjectIDs[member.Email]
		if !exists {
			log.L(ctx).Warnf("Azure Object ID not found for user %s", member.Email)
			continue
		}

		if err := p.removeRoleFromUser(ctx, objectID, role.Role.NameInProvider, subscriptionID); err != nil {
			log.L(ctx).Warnf("Failed to remove role from user %s: %v", member.Email, err)
		} else {
			log.L(ctx).Infof("Successfully removed role %s from user %s", role.Role.Name, member.Email)
		}
	}
	return nil
}

// removeRoleFromUser 从用户移除角色
func (p *Provider) removeRoleFromUser(ctx context.Context, objectID, roleGUID, subscriptionID string) error {
	roleManager, err := p.getRoleManager(subscriptionID)
	if err != nil {
		return fmt.Errorf("failed to create role manager: %w", err)
	}

	// 获取用户现有的角色分配
	assignments, err := roleManager.GetUserRoleAssignments(ctx, objectID)
	if err != nil {
		return fmt.Errorf("failed to get user role assignments: %w", err)
	}

	// 查找并删除匹配的角色分配
	for _, assignment := range assignments {
		if assignment.Properties != nil &&
			assignment.Properties.RoleDefinitionID != nil &&
			strings.Contains(*assignment.Properties.RoleDefinitionID, roleGUID) {

			err := roleManager.RemoveSubscriptionRole(ctx, *assignment.ID)
			if err != nil {
				return fmt.Errorf("failed to remove role assignment: %w", err)
			}
		}
	}
	return nil
}

// deleteAllUserRoles 删除所有用户角色
func (p *Provider) deleteAllUserRoles(ctx context.Context, roles []*modelv1.RoleMembers, subscriptionID string) error {
	roleManager, err := p.getRoleManager(subscriptionID)
	if err != nil {
		return fmt.Errorf("failed to create role manager: %w", err)
	}

	// 收集所有用户的邮箱
	var emails []string
	for _, role := range roles {
		for _, member := range role.Members {
			emails = append(emails, member.Email)
		}
	}

	// 通过邮箱获取Azure Object ID
	userObjectIDs, err := GetAzureUserObjectIDs(ctx, emails, p.config.TenantID, p.config.ClientID, p.config.ClientSecret)
	if err != nil {
		return fmt.Errorf("failed to get Azure Object IDs: %w", err)
	}

	// 为每个用户删除所有允许的角色
	for rolePattern := range modelv1.AzureAllowedRoles {
		for email, objectID := range userObjectIDs {
			// 获取用户现有的角色分配
			assignments, err := roleManager.GetUserRoleAssignments(ctx, objectID)
			if err != nil {
				log.L(ctx).Warnf("Failed to get user role assignments for %s: %v", email, err)
				continue
			}

			// 查找并删除匹配的角色分配
			for _, assignment := range assignments {
				if assignment.Properties != nil &&
					assignment.Properties.RoleDefinitionID != nil &&
					strings.Contains(*assignment.Properties.RoleDefinitionID, rolePattern) {

					err := roleManager.RemoveSubscriptionRole(ctx, *assignment.ID)
					if err != nil {
						log.L(ctx).Warnf("Failed to remove Azure role assignment for %s: %v", email, err)
					}
				}
			}
		}
		log.L(ctx).Infof("delete assignment %s policy success", rolePattern)
	}

	return nil
}

// extractEmails 提取邮箱列表
func (p *Provider) extractEmails(members []*modelv1.User) []string {
	emails := make([]string, 0, len(members))
	for _, member := range members {
		emails = append(emails, member.Email)
	}
	return emails
}

// GetProviderMembers 获取提供者成员信息
func (p *Provider) GetProviderMembers(ctx context.Context, provider string) ([]modelv1.ResourceMemberAccess, []uint64, error) {
	if p.store == nil {
		return nil, nil, errors.New("store not initialized")
	}

	// 先同步用户
	err := p.SyncUsers(ctx)
	if err != nil {
		log.L(ctx).Warnf("Failed to sync Azure users: %v", err)
	}

	return p.getAzureProviderMembers(ctx, provider)
}

// SyncUsers 同步用户到数据库
func (p *Provider) SyncUsers(ctx context.Context) error {
	if p.store == nil {
		return errors.New("store not initialized")
	}

	// 获取Azure凭据
	cred, err := p.getAzureCredential(ctx)
	if err != nil {
		log.L(ctx).Errorf("failed to get azure credentials:%s", err.Error())
		return err
	}

	// 获取Azure用户
	azureUsers, err := p.getAzureUsers(ctx, cred)
	if err != nil {
		log.L(ctx).Errorf("get azure users failed:%s", err.Error())
		return err
	}

	// 构建Azure用户映射
	azureUserMap := make(map[string]string) // email -> objectId
	for _, azUser := range azureUsers {
		azureUserMap[azUser.Email] = azUser.ObjectId
	}

	// 获取数据库中的用户
	users, err := p.store.User().Gets(ctx)
	if err != nil {
		log.L(ctx).Errorf("get user failed:%s", err.Error())
		return err
	}

	// 查找需要更新Azure Object ID的用户
	uUpdate := make([]*modelv1.User, 0)
	for _, u := range users {
		if objectId, exists := azureUserMap[u.Email]; exists {
			// 更新Azure Object ID
			if u.AzureObjectID == "" || u.AzureObjectID != objectId {
				u.AzureObjectID = objectId
				uUpdate = append(uUpdate, u)
			}
		}
	}

	// 批量保存更新的用户
	if len(uUpdate) > 0 {
		err = p.store.User().BatchSave(ctx, nil, uUpdate)
		if err != nil {
			log.L(ctx).Errorf("update azure user failed:%s", err.Error())
			return err
		}
	}

	log.L(ctx).Infof("sync azure user to db success, found %d azure users, updated: %d users", len(azureUsers), len(uUpdate))
	return nil
}

// SyncMembers 同步成员信息到数据库
func (p *Provider) SyncMembers(ctx context.Context) error {
	if p.store == nil {
		return errors.New("store not initialized")
	}

	providers := []string{"Azure"}

	var allMembers []modelv1.ResourceMemberAccess
	var allRoleIDs []uint64
	roleIDSet := make(map[uint64]bool)

	for _, provider := range providers {
		log.L(ctx).Infof("Starting sync for provider: %s", provider)

		members, roleIDs, err := p.getAzureProviderMembers(ctx, provider)
		if err != nil {
			log.L(ctx).Errorf("get %s members failed: %s", provider, err.Error())
			return err
		}

		// 收集所有成员记录
		allMembers = append(allMembers, members...)

		// 收集所有角色ID（去重）
		for _, roleID := range roleIDs {
			if !roleIDSet[roleID] {
				roleIDSet[roleID] = true
				allRoleIDs = append(allRoleIDs, roleID)
			}
		}

		log.L(ctx).Infof("Collected %d members from provider: %s", len(members), provider)
	}

	// 对所有成员记录进行去重
	uniqueMembers := p.deduplicateMembers(allMembers)
	log.L(ctx).Infof("After deduplication: %d unique members (removed %d duplicates)",
		len(uniqueMembers), len(allMembers)-len(uniqueMembers))

	// 统一同步到数据库
	membersInDB, err := p.store.ResourceMemberAccess().ListByRIDs(ctx, allRoleIDs)
	if err != nil {
		log.L(ctx).Error("failed to list members in db:" + err.Error())
		return err
	}

	add, del := p.diff(membersInDB, uniqueMembers)
	err = p.store.ResourceMemberAccess().SyncToDB(ctx, add, del)
	if err != nil {
		log.L(ctx).Error("sync azure members to db failed:" + err.Error())
		return err
	}

	log.L(ctx).Infof("sync azure members to db success, added: %d, deleted: %d", len(add), len(del))
	return nil
}

// GetAzureCredential 获取Azure凭据（公开方法）
func (p *Provider) GetAzureCredential(ctx context.Context) (azcore.TokenCredential, error) {
	return p.getAzureCredential(ctx)
}

// getAzureCredential 获取Azure凭据
func (p *Provider) getAzureCredential(ctx context.Context) (azcore.TokenCredential, error) {
	// 尝试不同的凭据方法

	// 1. 尝试服务主体与客户端密钥
	if clientID := viper.GetString("azure.client_id"); clientID != "" {
		if clientSecret := viper.GetString("azure.client_secret"); clientSecret != "" {
			if tenantID := viper.GetString("azure.tenant_id"); tenantID != "" {
				cred, err := azidentity.NewClientSecretCredential(tenantID, clientID, clientSecret, nil)
				if err == nil {
					return cred, nil
				}
				log.L(ctx).Warn("failed to use client secret credential:" + err.Error())
			}
		}
	}

	// 2. 尝试托管身份
	cred, err := azidentity.NewDefaultAzureCredential(nil)
	if err != nil {
		log.L(ctx).Error("failed to get azure default credential:" + err.Error())
		return nil, err
	}

	return cred, nil
}
