package host

import (
	"context"
	"strings"

	"hyapp/pkg/xerr"
)

type RoleScope string

const (
	RoleScopeCountry RoleScope = "country"
	RoleScopeRegion  RoleScope = "region"
	RoleScopeGlobal  RoleScope = "global"

	RoleScopeSceneOrganizationExpansion = "organization_role_expansion"
	RoleScopeSceneManagerOperations     = "manager_operations"
	// RoleScopeSceneManagerAddBDLeader 兼容上一版 gateway/admin 的策略查询，解析后统一返回 manager_operations。
	RoleScopeSceneManagerAddBDLeader = "manager_add_bd_leader"
)

// RoleScopePolicy 是 user-service 拥有的 App 范围策略；调用方只消费解析结果，不能再按产品名复制分支。
type RoleScopePolicy struct {
	Scene                       string
	BaseScope                   RoleScope
	ExpandedScope               RoleScope
	RegionExpansionConfigurable bool
	UpdatedAtMS                 int64
}

// RoleScopePolicyRepository 只暴露小配置表的精确键读取和原子批量写入，避免把后台配置混入 Host 关系事务接口。
type RoleScopePolicyRepository interface {
	GetRoleScopePolicy(ctx context.Context, scene string) (RoleScopePolicy, bool, error)
	UpsertRoleScopePolicies(ctx context.Context, policies []RoleScopePolicy, updatedAtMS int64) ([]RoleScopePolicy, error)
}

// DefaultRoleScopePolicy 定义未配置新 App 的安全基线。产品差异必须写入 owner 表，不能再扩展代码注册表。
func DefaultRoleScopePolicy(rawScene string) (RoleScopePolicy, error) {
	scene := normalizeRoleScopeScene(rawScene)
	switch scene {
	case RoleScopeSceneOrganizationExpansion:
		return RoleScopePolicy{
			Scene:         scene,
			BaseScope:     RoleScopeRegion,
			ExpandedScope: RoleScopeRegion,
		}, nil
	case RoleScopeSceneManagerOperations:
		return RoleScopePolicy{
			Scene:                       scene,
			BaseScope:                   RoleScopeCountry,
			ExpandedScope:               RoleScopeRegion,
			RegionExpansionConfigurable: true,
		}, nil
	default:
		return RoleScopePolicy{}, xerr.New(xerr.InvalidArgument, "role scope scene is invalid")
	}
}

// ResolveRoleScopePolicy 先验证 scene，再读取 user DB 的 App 精确配置；数据库错误必须向上返回，不能降级扩大权限。
func ResolveRoleScopePolicy(ctx context.Context, repository RoleScopePolicyRepository, rawScene string) (RoleScopePolicy, error) {
	defaultPolicy, err := DefaultRoleScopePolicy(rawScene)
	if err != nil {
		return RoleScopePolicy{}, err
	}
	if repository == nil {
		return RoleScopePolicy{}, xerr.New(xerr.Unavailable, "role scope policy repository is not configured")
	}
	policy, found, err := repository.GetRoleScopePolicy(ctx, defaultPolicy.Scene)
	if err != nil {
		return RoleScopePolicy{}, err
	}
	if !found {
		return defaultPolicy, nil
	}
	policy.Scene = defaultPolicy.Scene
	if err := validateRoleScopePolicy(policy); err != nil {
		return RoleScopePolicy{}, err
	}
	return policy, nil
}

// ResolveRoleScopePolicy 是 Host service 内所有角色边界查询的统一入口。
func (s *Service) ResolveRoleScopePolicy(ctx context.Context, rawScene string) (RoleScopePolicy, error) {
	return ResolveRoleScopePolicy(ctx, s.roleScopePolicyRepository, rawScene)
}

// UpdateRoleScopePolicies 把两个 scene 作为同一 App 配置快照提交，避免后台只写一半后留下混合语义。
func (s *Service) UpdateRoleScopePolicies(ctx context.Context, policies []RoleScopePolicy) ([]RoleScopePolicy, error) {
	if s == nil || s.roleScopePolicyRepository == nil {
		return nil, xerr.New(xerr.Unavailable, "role scope policy repository is not configured")
	}
	if len(policies) != 2 {
		return nil, xerr.New(xerr.InvalidArgument, "both role scope policies are required")
	}
	seen := make(map[string]struct{}, len(policies))
	normalized := make([]RoleScopePolicy, 0, len(policies))
	for _, policy := range policies {
		policy.Scene = normalizeRoleScopeScene(policy.Scene)
		if _, exists := seen[policy.Scene]; exists {
			return nil, xerr.New(xerr.InvalidArgument, "role scope scene is duplicated")
		}
		if err := validateRoleScopePolicy(policy); err != nil {
			return nil, err
		}
		seen[policy.Scene] = struct{}{}
		normalized = append(normalized, policy)
	}
	if _, ok := seen[RoleScopeSceneOrganizationExpansion]; !ok {
		return nil, xerr.New(xerr.InvalidArgument, "organization role scope policy is required")
	}
	if _, ok := seen[RoleScopeSceneManagerOperations]; !ok {
		return nil, xerr.New(xerr.InvalidArgument, "manager role scope policy is required")
	}
	return s.roleScopePolicyRepository.UpsertRoleScopePolicies(ctx, normalized, s.now().UTC().UnixMilli())
}

func normalizeRoleScopeScene(rawScene string) string {
	scene := strings.ToLower(strings.TrimSpace(rawScene))
	if scene == RoleScopeSceneManagerAddBDLeader {
		return RoleScopeSceneManagerOperations
	}
	return scene
}

func validateRoleScopePolicy(policy RoleScopePolicy) error {
	if policy.Scene != RoleScopeSceneOrganizationExpansion && policy.Scene != RoleScopeSceneManagerOperations {
		return xerr.New(xerr.InvalidArgument, "role scope scene is invalid")
	}
	if !validRoleScope(policy.BaseScope) || !validRoleScope(policy.ExpandedScope) {
		return xerr.New(xerr.InvalidArgument, "role scope is invalid")
	}
	if policy.Scene == RoleScopeSceneOrganizationExpansion {
		if policy.BaseScope == RoleScopeCountry || policy.RegionExpansionConfigurable || policy.ExpandedScope != policy.BaseScope {
			return xerr.New(xerr.InvalidArgument, "organization role scope policy is invalid")
		}
		return nil
	}
	if !policy.RegionExpansionConfigurable && policy.ExpandedScope != policy.BaseScope {
		return xerr.New(xerr.InvalidArgument, "non-configurable manager scope must keep one scope")
	}
	if policy.RegionExpansionConfigurable && roleScopeRank(policy.ExpandedScope) < roleScopeRank(policy.BaseScope) {
		return xerr.New(xerr.InvalidArgument, "expanded manager scope cannot be narrower than base scope")
	}
	return nil
}

func validRoleScope(scope RoleScope) bool {
	return scope == RoleScopeCountry || scope == RoleScopeRegion || scope == RoleScopeGlobal
}

func roleScopeRank(scope RoleScope) int {
	switch scope {
	case RoleScopeCountry:
		return 1
	case RoleScopeRegion:
		return 2
	case RoleScopeGlobal:
		return 3
	default:
		return 0
	}
}

// EffectiveScope 只允许声明为 configurable 的策略接受经理个人扩区开关。
func (p RoleScopePolicy) EffectiveScope(regionExpansionEnabled bool) RoleScope {
	if p.RegionExpansionConfigurable && regionExpansionEnabled {
		return p.ExpandedScope
	}
	return p.BaseScope
}
