package host

import (
	"context"
	"testing"
	"time"
)

type fakeRoleScopePolicyRepository struct {
	policy RoleScopePolicy
	found  bool
	err    error
}

func (r *fakeRoleScopePolicyRepository) GetRoleScopePolicy(context.Context, string) (RoleScopePolicy, bool, error) {
	return r.policy, r.found, r.err
}

func (r *fakeRoleScopePolicyRepository) UpsertRoleScopePolicies(_ context.Context, policies []RoleScopePolicy, updatedAtMS int64) ([]RoleScopePolicy, error) {
	for index := range policies {
		policies[index].UpdatedAtMS = updatedAtMS
	}
	return policies, r.err
}

func TestResolveRoleScopePolicyUsesOwnerConfigOrGenericDefault(t *testing.T) {
	tests := []struct {
		name         string
		repository   *fakeRoleScopePolicyRepository
		baseScope    RoleScope
		configurable bool
		expanded     RoleScope
	}{
		{
			name:         "new app uses generic default",
			repository:   &fakeRoleScopePolicyRepository{},
			baseScope:    RoleScopeCountry,
			configurable: true,
			expanded:     RoleScopeRegion,
		},
		{
			name: "stored owner config is authoritative",
			repository: &fakeRoleScopePolicyRepository{found: true, policy: RoleScopePolicy{
				Scene:         RoleScopeSceneManagerOperations,
				BaseScope:     RoleScopeGlobal,
				ExpandedScope: RoleScopeGlobal,
			}},
			baseScope: RoleScopeGlobal,
			expanded:  RoleScopeGlobal,
		},
	}
	for _, testCase := range tests {
		t.Run(testCase.name, func(t *testing.T) {
			policy, err := ResolveRoleScopePolicy(context.Background(), testCase.repository, RoleScopeSceneManagerOperations)
			if err != nil {
				t.Fatalf("resolve policy: %v", err)
			}
			if policy.BaseScope != testCase.baseScope || policy.RegionExpansionConfigurable != testCase.configurable {
				t.Fatalf("policy mismatch: %+v", policy)
			}
			if got := policy.EffectiveScope(true); got != testCase.expanded {
				t.Fatalf("expanded scope = %q, want %q", got, testCase.expanded)
			}
		})
	}
}

func TestDefaultRoleScopePolicyKeepsLegacyManagerSceneCompatible(t *testing.T) {
	policy, err := DefaultRoleScopePolicy(RoleScopeSceneManagerAddBDLeader)
	if err != nil {
		t.Fatalf("resolve legacy manager scene: %v", err)
	}
	if policy.Scene != RoleScopeSceneManagerOperations || policy.ExpandedScope != RoleScopeRegion {
		t.Fatalf("legacy scene must resolve to general manager policy: %+v", policy)
	}
}

func TestUpdateRoleScopePoliciesRejectsPartialOrNarrowerSnapshots(t *testing.T) {
	svc := New(nil, WithClock(func() time.Time { return time.UnixMilli(123).UTC() }))
	svc.roleScopePolicyRepository = &fakeRoleScopePolicyRepository{}
	if _, err := svc.UpdateRoleScopePolicies(context.Background(), []RoleScopePolicy{{
		Scene:         RoleScopeSceneOrganizationExpansion,
		BaseScope:     RoleScopeRegion,
		ExpandedScope: RoleScopeRegion,
	}}); err == nil {
		t.Fatal("partial role scope snapshot must be rejected")
	}
	if _, err := svc.UpdateRoleScopePolicies(context.Background(), []RoleScopePolicy{
		{Scene: RoleScopeSceneOrganizationExpansion, BaseScope: RoleScopeRegion, ExpandedScope: RoleScopeRegion},
		{Scene: RoleScopeSceneManagerOperations, BaseScope: RoleScopeGlobal, ExpandedScope: RoleScopeCountry, RegionExpansionConfigurable: true},
	}); err == nil {
		t.Fatal("narrower expanded manager scope must be rejected")
	}
}
