package migration

import "testing"

func TestInviteEmailMatchesIdentityExact(t *testing.T) {
	id := ClaimIdentity{Email: "Alice@Acme.com"}
	if !InviteEmailMatchesIdentity("alice@acme.com", nil, "", id) {
		t.Fatal("expected case-insensitive exact match")
	}
}

func TestInviteEmailMatchesIdentityPreferredUsername(t *testing.T) {
	id := ClaimIdentity{
		Email:             "alice.smith@acme.com",
		PreferredUsername: "alice@acme.com",
	}
	if !InviteEmailMatchesIdentity("alice@acme.com", nil, "", id) {
		t.Fatal("expected preferred_username match")
	}
}

func TestInviteEmailMatchesIdentityUPN(t *testing.T) {
	id := ClaimIdentity{
		Email: "alice.smith@acme.com",
		UPN:   "alice@acme.com",
	}
	if !InviteEmailMatchesIdentity("alice@acme.com", nil, "", id) {
		t.Fatal("expected upn match")
	}
}

func TestInviteEmailMatchesIdentityAlternateEmail(t *testing.T) {
	id := ClaimIdentity{Email: "alice.smith@acme.com"}
	if !InviteEmailMatchesIdentity("alice@acme.com", []string{"alice.smith@acme.com"}, "", id) {
		t.Fatal("expected alternate email match")
	}
}

func TestInviteEmailMatchesIdentityGmailDotAlias(t *testing.T) {
	id := ClaimIdentity{Email: "alice.smith@acme.com"}
	if !InviteEmailMatchesIdentity("alice.smith@acme.com", nil, "", id) {
		t.Fatal("expected exact match baseline")
	}
	id = ClaimIdentity{Email: "a.l.i.c.e.smith@gmail.com"}
	if !InviteEmailMatchesIdentity("alice.smith@gmail.com", nil, "", id) {
		t.Fatal("expected dot-insensitive local-part match on gmail.com")
	}
	id = ClaimIdentity{Email: "a.l.i.c.e.smith@acme.com"}
	if InviteEmailMatchesIdentity("alice.smith@acme.com", nil, "", id) {
		t.Fatal("expected reject dot-alias on non-gmail domain")
	}
}

func TestInviteEmailMatchesIdentityPlusTag(t *testing.T) {
	id := ClaimIdentity{Email: "alice+tag@gmail.com"}
	if !InviteEmailMatchesIdentity("alice@gmail.com", nil, "", id) {
		t.Fatal("expected plus-tag stripped match on gmail.com")
	}
	id = ClaimIdentity{Email: "alice+tag@acme.com"}
	if InviteEmailMatchesIdentity("alice@acme.com", nil, "", id) {
		t.Fatal("expected reject plus-tag alias on non-gmail domain")
	}
}

func TestInviteEmailMatchesIdentityProjectDomainUPN(t *testing.T) {
	id := ClaimIdentity{
		Email:             "alice.smith@acme.com",
		PreferredUsername: "alice@contoso.onmicrosoft.com",
	}
	if !InviteEmailMatchesIdentity("alice@acme.com", nil, "acme.com", id) {
		t.Fatal("expected project-domain UPN local-part match")
	}
}

func TestInviteEmailMatchesIdentityRejectsDifferentUserSameDomain(t *testing.T) {
	id := ClaimIdentity{Email: "bob@acme.com"}
	if InviteEmailMatchesIdentity("alice@acme.com", nil, "acme.com", id) {
		t.Fatal("expected reject for different local-part on same domain")
	}
}

func TestInviteEmailMatchesIdentityRejectsUnrelatedDomain(t *testing.T) {
	id := ClaimIdentity{Email: "alice@evil.com"}
	if InviteEmailMatchesIdentity("alice@acme.com", nil, "", id) {
		t.Fatal("expected reject for different domain without alias")
	}
}

func TestInviteEmailMatchesIdentityEmptyIdentity(t *testing.T) {
	if InviteEmailMatchesIdentity("alice@acme.com", nil, "", ClaimIdentity{}) {
		t.Fatal("expected reject for empty identity")
	}
}

func TestInviteEmailMatchesIdentityIgnoresNonEmailPreferredUsername(t *testing.T) {
	id := ClaimIdentity{PreferredUsername: "alice"}
	if InviteEmailMatchesIdentity("alice@acme.com", nil, "", id) {
		t.Fatal("expected reject when preferred_username is not an email")
	}
}

func TestValidateMicrosoftTenantClaim(t *testing.T) {
	msProj := Project{SourceProvider: "microsoft", MicrosoftTenantID: "tenant-abc"}
	if err := validateMicrosoftTenantClaim(msProj, "tenant-abc"); err != nil {
		t.Fatalf("expected match: %v", err)
	}
	if err := validateMicrosoftTenantClaim(msProj, "TENANT-ABC"); err != nil {
		t.Fatalf("expected case-insensitive match: %v", err)
	}
	if err := validateMicrosoftTenantClaim(msProj, "other-tenant"); err != ErrTenantMismatch {
		t.Fatalf("expected tenant mismatch, got %v", err)
	}
	if err := validateMicrosoftTenantClaim(msProj, ""); err != ErrTenantMismatch {
		t.Fatalf("expected reject empty tid when tenant pinned: %v", err)
	}

	googleProj := Project{SourceProvider: "google", MicrosoftTenantID: "tenant-abc"}
	if err := validateMicrosoftTenantClaim(googleProj, "wrong"); err != nil {
		t.Fatalf("google project should ignore tenant: %v", err)
	}

	noTenant := Project{SourceProvider: "microsoft"}
	if err := validateMicrosoftTenantClaim(noTenant, "any"); err != nil {
		t.Fatalf("expected skip when project tenant unset: %v", err)
	}
}
