package service

import (
	"baron-sso-backend/internal/domain"
	"encoding/json"
	"strings"
	"testing"

	"github.com/stretchr/testify/require"
)

func TestBuildWorksmobileOrgUnitPayloadUsesTenantExternalKeyAndEnvDomainClassification(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	parentID := "11111111-1111-1111-1111-111111111111"
	tenant := domain.Tenant{
		ID:       "22222222-2222-2222-2222-222222222222",
		Slug:     "tech-dev-center",
		Name:     "Saman Engineering",
		ParentID: &parentID,
		Domains: []domain.TenantDomain{
			{Domain: "samaneng.com"},
		},
	}
	rootConfig := domain.JSONMap{
		"worksmobile": map[string]any{
			"domainMappings": map[string]any{
				"samaneng.com": float64(9999),
			},
		},
	}

	payload, err := BuildWorksmobileOrgUnitPayload(tenant, rootConfig, 7)

	require.NoError(t, err)
	require.Equal(t, int64(1001), payload.DomainID)
	require.Equal(t, "Saman Engineering", payload.OrgUnitName)
	require.Equal(t, "tech-dev-center@samaneng.com", payload.Email)
	require.Equal(t, tenant.ID, payload.OrgUnitExternalKey)
	require.Equal(t, "externalKey:"+parentID, payload.ParentOrgUnitID)
	require.Equal(t, 7, payload.DisplayOrder)
}

func TestBuildWorksmobileOrgUnitPayloadUsesWorksmobileMailDomainForBarongroup(t *testing.T) {
	t.Setenv("BARONGROUP_DOMAIN_ID", "1004")
	tenant := domain.Tenant{
		ID:      "11111111-1111-1111-1111-111111111111",
		Slug:    "jangheon",
		Name:    "(주)장헌",
		Type:    domain.TenantTypeCompany,
		Domains: []domain.TenantDomain{{Domain: "jangheon.com"}},
	}

	payload, err := BuildWorksmobileOrgUnitPayloadForDomainTenant(tenant, tenant, nil, 1)

	require.NoError(t, err)
	require.Equal(t, int64(1004), payload.DomainID)
	require.Equal(t, "jangheon@brsw.kr", payload.Email)
}

func TestBuildWorksmobileOrgUnitPayloadDefaultsDisplayOrderToOne(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	tenant := domain.Tenant{
		ID:      "11111111-1111-1111-1111-111111111111",
		Slug:    "tech-dev-center",
		Name:    "기술개발센터",
		Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
	}

	payload, err := BuildWorksmobileOrgUnitPayload(tenant, nil, 0)

	require.NoError(t, err)
	require.Equal(t, 1, payload.DisplayOrder)
}

func TestNormalizeRootChildWorksmobileOrgUnitParentClearsCrossDomainParent(t *testing.T) {
	rootID := "038326b6-954a-48a7-a85f-efd83f62b82a"
	payload := WorksmobileOrgUnitPayload{ParentOrgUnitID: "externalKey:" + rootID}
	tenant := domain.Tenant{ParentID: &rootID}

	normalized := normalizeWorksmobileOrgUnitParent(payload, tenant, nil, rootID)

	require.Empty(t, normalized.ParentOrgUnitID)
}

func TestBuildWorksmobileUserPayloadMapsBaronUserAndPrimaryTenant(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	rootTenantID := "11111111-1111-1111-1111-111111111111"
	tenantID := "33333333-3333-3333-3333-333333333333"
	user := domain.User{
		ID:       "44444444-4444-4444-4444-444444444444",
		Email:    "john1@samaneng.com",
		Name:     "John Doe",
		Phone:    "+19144812222",
		Position: "Manager",
		JobTitle: "Sales management",
		TenantID: &tenantID,
		Metadata: domain.JSONMap{
			"employee_id": "AB001",
		},
	}
	tenant := domain.Tenant{
		ID:       tenantID,
		Slug:     "sales",
		Name:     "Sales",
		Type:     domain.TenantTypeOrganization,
		ParentID: &rootTenantID,
	}
	rootTenant := domain.Tenant{
		ID:      rootTenantID,
		Slug:    "saman",
		Name:    "삼안",
		Type:    domain.TenantTypeCompany,
		Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
	}
	rootConfig := domain.JSONMap{
		"worksmobile": map[string]any{
			"domainMappings": map[string]any{
				"samaneng.com": int64(9999),
			},
		},
	}

	payload, err := BuildWorksmobileUserPayloadForDomainTenants(
		user,
		tenant,
		map[string]domain.Tenant{
			rootTenantID: rootTenant,
			tenantID:     tenant,
		},
		rootConfig,
	)

	require.NoError(t, err)
	require.Equal(t, int64(1001), payload.DomainID)
	require.Equal(t, "john1@samaneng.com", payload.Email)
	require.Equal(t, user.ID, payload.UserExternalKey)
	require.Equal(t, "John Doe", payload.UserName.LastName)
	require.Equal(t, "+19144812222", payload.CellPhone)
	require.Equal(t, "AB001", payload.EmployeeNumber)
	require.Equal(t, "Sales management", payload.Task)
	require.Empty(t, payload.PrivateEmail)
	require.Empty(t, payload.AliasEmails)
	require.Equal(t, "ko_KR", payload.Locale)
	require.Empty(t, payload.PasswordConfig.PasswordCreationType)
	require.Empty(t, payload.PasswordConfig.Password)
	require.Len(t, payload.Organizations, 1)
	require.Equal(t, int64(1001), payload.Organizations[0].DomainID)
	require.True(t, payload.Organizations[0].Primary)
	require.Equal(t, "externalKey:"+tenantID, payload.Organizations[0].OrgUnits[0].OrgUnitID)
}

func TestBuildWorksmobileUserPayloadDeduplicatesKoreanCountryCodeInCellPhone(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	tenantID := "33333333-3333-3333-3333-333333333333"
	user := domain.User{
		ID:       "44444444-4444-4444-4444-444444444444",
		Email:    "john1@samaneng.com",
		Name:     "John Doe",
		Phone:    "+82 +821091917771",
		TenantID: &tenantID,
	}
	tenant := domain.Tenant{
		ID:      tenantID,
		Slug:    "saman",
		Name:    "Saman",
		Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
	}

	payload, err := BuildWorksmobileUserPayload(user, tenant, nil)

	require.NoError(t, err)
	require.Equal(t, "+821091917771", payload.CellPhone)
}

func TestWorksmobileUserPayloadJSONOmitsEmptyPasswordConfig(t *testing.T) {
	data, err := json.Marshal(WorksmobileUserPayload{
		DomainID:        1001,
		Email:           "target@samaneng.com",
		UserExternalKey: "user-1",
		UserName:        WorksmobileUserName{LastName: "Target"},
	})

	require.NoError(t, err)
	require.NotContains(t, string(data), "passwordConfig")
}

func TestBuildWorksmobileUserPayloadOmitsOrganizationsForSamanRootTenant(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	tenantID := "33333333-3333-3333-3333-333333333333"
	user := domain.User{
		ID:       "44444444-4444-4444-4444-444444444444",
		Email:    "root-user@samaneng.com",
		Name:     "Root User",
		JobTitle: "Advisor",
		TenantID: &tenantID,
	}
	tenant := domain.Tenant{
		ID:      tenantID,
		Slug:    "saman",
		Name:    "삼안",
		Type:    domain.TenantTypeCompany,
		Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
	}

	payload, err := BuildWorksmobileUserPayload(user, tenant, nil)

	require.NoError(t, err)
	require.Equal(t, int64(1001), payload.DomainID)
	require.Equal(t, "root-user@samaneng.com", payload.Email)
	require.Equal(t, "Advisor", payload.Task)
	require.Empty(t, payload.Organizations)
}

func TestBuildWorksmobileUserPayloadNormalizesLegacyCharacterMapEmployeeID(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	tenantID := "33333333-3333-3333-3333-333333333333"
	user := domain.User{
		ID:       "44444444-4444-4444-4444-444444444444",
		Email:    "john1@samaneng.com",
		Name:     "John Doe",
		TenantID: &tenantID,
		Metadata: domain.JSONMap{
			"employee_id": map[string]any{
				"0": "j",
				"1": "o",
				"2": "h",
				"3": "n",
			},
		},
	}
	tenant := domain.Tenant{
		ID:      tenantID,
		Slug:    "saman",
		Name:    "Saman",
		Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
	}

	payload, err := BuildWorksmobileUserPayload(user, tenant, nil)

	require.NoError(t, err)
	require.Equal(t, "john", payload.EmployeeNumber)
}

func TestBuildWorksmobileUserPayloadMapsAdditionalAppointmentsToOrgUnits(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	t.Setenv("HANMAC_DOMAIN_ID", "1002")
	samanRootID := "11111111-1111-1111-1111-111111111111"
	hanmacRootID := "22222222-2222-2222-2222-222222222222"
	primaryTenantID := "33333333-3333-3333-3333-333333333333"
	secondaryTenantID := "55555555-5555-5555-5555-555555555555"
	user := domain.User{
		ID:       "44444444-4444-4444-4444-444444444444",
		Email:    "john1@samaneng.com",
		Name:     "John Doe",
		Phone:    "+19144812222",
		TenantID: &primaryTenantID,
		Metadata: domain.JSONMap{
			"additionalAppointments": []any{
				map[string]any{
					"tenantId":  secondaryTenantID,
					"isPrimary": false,
					"isManager": true,
					"jobTitle":  "PM",
					"position":  "팀장",
				},
				map[string]any{
					"tenantId":  primaryTenantID,
					"isPrimary": true,
					"isOwner":   true,
					"jobTitle":  "Engineering",
					"position":  "책임",
				},
			},
		},
	}
	samanRoot := domain.Tenant{
		ID:      samanRootID,
		Slug:    "saman",
		Name:    "삼안",
		Type:    domain.TenantTypeCompany,
		Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
	}
	hanmacRoot := domain.Tenant{
		ID:      hanmacRootID,
		Slug:    "hanmac",
		Name:    "한맥기술",
		Type:    domain.TenantTypeCompany,
		Domains: []domain.TenantDomain{{Domain: "hanmaceng.co.kr"}},
	}
	primaryTenant := domain.Tenant{
		ID:       primaryTenantID,
		Slug:     "saman-sales",
		Name:     "Saman Sales",
		Type:     domain.TenantTypeOrganization,
		ParentID: &samanRootID,
	}
	secondaryTenant := domain.Tenant{
		ID:       secondaryTenantID,
		Slug:     "hanmac-sales",
		Name:     "Hanmac Sales",
		Type:     domain.TenantTypeOrganization,
		ParentID: &hanmacRootID,
	}

	payload, err := BuildWorksmobileUserPayloadForDomainTenants(
		user,
		primaryTenant,
		map[string]domain.Tenant{
			samanRootID:       samanRoot,
			hanmacRootID:      hanmacRoot,
			primaryTenantID:   primaryTenant,
			secondaryTenantID: secondaryTenant,
		},
		nil,
	)

	require.NoError(t, err)
	require.Equal(t, "Engineering", payload.Task)
	require.Len(t, payload.Organizations, 2)
	require.Equal(t, int64(1001), payload.Organizations[0].DomainID)
	require.True(t, payload.Organizations[0].Primary)
	require.Equal(t, "externalKey:"+primaryTenantID, payload.Organizations[0].OrgUnits[0].OrgUnitID)
	require.True(t, payload.Organizations[0].OrgUnits[0].Primary)
	require.Nil(t, payload.Organizations[0].OrgUnits[0].IsManager)
	require.Equal(t, int64(1002), payload.Organizations[1].DomainID)
	require.False(t, payload.Organizations[1].Primary)
	require.Equal(t, "externalKey:"+secondaryTenantID, payload.Organizations[1].OrgUnits[0].OrgUnitID)
	require.True(t, payload.Organizations[1].OrgUnits[0].Primary)
	require.NotNil(t, payload.Organizations[1].OrgUnits[0].IsManager)
	require.True(t, *payload.Organizations[1].OrgUnits[0].IsManager)
}

func TestBuildWorksmobileUserPayloadKeepsPrimaryTenantWhenEmailDomainAppointmentExists(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	rootTenantID := "9caf62e1-297d-4e8f-870b-61780998bbeb"
	primaryTenantID := "1edc196d-020c-4519-9ec4-3d23b99076e6"
	user := domain.User{
		ID:       "64231465-d5c0-4085-b4a2-603b90834f86",
		Email:    "evenlee@samaneng.com",
		Name:     "이용운",
		JobTitle: "부사장",
		TenantID: &primaryTenantID,
		Metadata: domain.JSONMap{
			"additionalAppointments": []any{
				map[string]any{
					"tenantId":         rootTenantID,
					"tenantSlug":       "saman",
					"tenantName":       "삼안",
					"assignmentSource": "email_domain",
					"sourceDomain":     "samaneng.com",
				},
			},
		},
	}
	rootTenant := domain.Tenant{
		ID:      rootTenantID,
		Slug:    "saman",
		Name:    "삼안",
		Type:    domain.TenantTypeCompany,
		Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
	}
	primaryTenant := domain.Tenant{
		ID:       primaryTenantID,
		Slug:     "asset-management",
		Name:     "자산관리",
		Type:     domain.TenantTypeOrganization,
		ParentID: &rootTenantID,
	}

	payload, err := BuildWorksmobileUserPayloadForDomainTenants(
		user,
		primaryTenant,
		map[string]domain.Tenant{
			rootTenantID:    rootTenant,
			primaryTenantID: primaryTenant,
		},
		nil,
	)

	require.NoError(t, err)
	require.Len(t, payload.Organizations, 1)
	require.Equal(t, int64(1001), payload.Organizations[0].DomainID)
	require.True(t, payload.Organizations[0].Primary)
	require.Len(t, payload.Organizations[0].OrgUnits, 1)
	require.Equal(t, "externalKey:"+primaryTenantID, payload.Organizations[0].OrgUnits[0].OrgUnitID)
	require.True(t, payload.Organizations[0].OrgUnits[0].Primary)
}

func TestBuildWorksmobileUserPayloadKeepsFirstAffiliationPrimaryWhenBaronRepresentativeIsGPDTDC(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	t.Setenv("GPDTDC_DOMAIN_ID", "1003")
	samanRootID := "11111111-1111-1111-1111-111111111111"
	gpdtdcID := "5530ca6e-c5e6-4bf0-84d6-76c6a8fb70ee"
	firstTenantID := "33333333-3333-3333-3333-333333333333"
	secondTenantID := "55555555-5555-5555-5555-555555555555"
	user := domain.User{
		ID:       "44444444-4444-4444-4444-444444444444",
		Email:    "gpdtdc-dual@samaneng.com",
		Name:     "GPDTDC Dual User",
		TenantID: &gpdtdcID,
		Metadata: domain.JSONMap{
			"additionalAppointments": []any{
				map[string]any{
					"tenantId":  firstTenantID,
					"isPrimary": true,
					"jobTitle":  "First affiliation task",
				},
				map[string]any{
					"tenantId":  secondTenantID,
					"isPrimary": false,
					"jobTitle":  "Second affiliation task",
				},
			},
		},
	}
	gpdtdcTenant := domain.Tenant{
		ID:   gpdtdcID,
		Slug: "gpdtdc",
		Name: "총괄기획&기술개발센터",
	}
	samanRoot := domain.Tenant{
		ID:      samanRootID,
		Slug:    "saman",
		Name:    "삼안",
		Type:    domain.TenantTypeCompany,
		Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
	}
	firstTenant := domain.Tenant{
		ID:       firstTenantID,
		Slug:     "rnd-center",
		Name:     "삼안기술개발센터",
		Type:     domain.TenantTypeOrganization,
		ParentID: &samanRootID,
	}
	secondTenant := domain.Tenant{
		ID:       secondTenantID,
		Slug:     "tdc",
		Name:     "기술개발센터",
		ParentID: &gpdtdcID,
	}

	payload, err := BuildWorksmobileUserPayloadForDomainTenants(
		user,
		gpdtdcTenant,
		map[string]domain.Tenant{
			samanRootID:    samanRoot,
			gpdtdcID:       gpdtdcTenant,
			firstTenantID:  firstTenant,
			secondTenantID: secondTenant,
		},
		nil,
	)

	require.NoError(t, err)
	require.Equal(t, int64(1001), payload.DomainID)
	require.Equal(t, "First affiliation task", payload.Task)
	require.Len(t, payload.Organizations, 2)
	require.Equal(t, int64(1001), payload.Organizations[0].DomainID)
	require.True(t, payload.Organizations[0].Primary)
	require.Equal(t, "externalKey:"+firstTenantID, payload.Organizations[0].OrgUnits[0].OrgUnitID)
	require.True(t, payload.Organizations[0].OrgUnits[0].Primary)
	require.Equal(t, int64(1003), payload.Organizations[1].DomainID)
	require.False(t, payload.Organizations[1].Primary)
	require.Equal(t, "externalKey:"+secondTenantID, payload.Organizations[1].OrgUnits[0].OrgUnitID)
	require.True(t, payload.Organizations[1].OrgUnits[0].Primary)
}

func TestBuildWorksmobileUserPayloadUsesEmailDomainForAccountDomainWhenPrimaryOrgIsGPDTDC(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	t.Setenv("GPDTDC_DOMAIN_ID", "1003")
	samanID := "11111111-1111-1111-1111-111111111111"
	gpdtdcID := "5530ca6e-c5e6-4bf0-84d6-76c6a8fb70ee"
	leafTenantID := "52f06c97-9d6f-4819-971b-43303062e193"
	user := domain.User{
		ID:       "44444444-4444-4444-4444-444444444444",
		Email:    "dhlee@samaneng.com",
		Name:     "GPDTDC Saman User",
		TenantID: &leafTenantID,
		Metadata: domain.JSONMap{
			"additionalAppointments": []any{
				map[string]any{
					"tenantId":  leafTenantID,
					"isPrimary": true,
				},
			},
		},
	}
	samanTenant := domain.Tenant{
		ID:      samanID,
		Slug:    "saman",
		Name:    "삼안",
		Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
	}
	gpdtdcTenant := domain.Tenant{
		ID:   gpdtdcID,
		Slug: "gpdtdc",
		Name: "총괄기획&기술개발센터",
	}
	leafTenant := domain.Tenant{
		ID:       leafTenantID,
		Slug:     "infra-bim2",
		Name:     "인프라 BIM2",
		ParentID: &gpdtdcID,
	}

	payload, err := BuildWorksmobileUserPayloadForDomainTenants(
		user,
		leafTenant,
		map[string]domain.Tenant{
			samanID:      samanTenant,
			gpdtdcID:     gpdtdcTenant,
			leafTenantID: leafTenant,
		},
		nil,
	)

	require.NoError(t, err)
	require.Equal(t, int64(1001), payload.DomainID)
	require.Len(t, payload.Organizations, 1)
	require.Equal(t, int64(1003), payload.Organizations[0].DomainID)
	require.True(t, payload.Organizations[0].Primary)
	require.Equal(t, "dhlee@baroncs.co.kr", payload.Organizations[0].Email)
	require.Equal(t, "externalKey:"+leafTenantID, payload.Organizations[0].OrgUnits[0].OrgUnitID)
	require.True(t, payload.Organizations[0].OrgUnits[0].Primary)
}

func TestWorksmobileUserPayloadJSONIncludesFalsePrimaryFields(t *testing.T) {
	payload := WorksmobileUserPayload{
		Email: "user@samaneng.com",
		Organizations: []WorksmobileUserOrganization{
			{
				DomainID: 1001,
				Primary:  true,
				OrgUnits: []WorksmobileUserOrgUnit{
					{OrgUnitID: "externalKey:primary", Primary: true},
				},
			},
			{
				DomainID: 1003,
				Primary:  false,
				OrgUnits: []WorksmobileUserOrgUnit{
					{OrgUnitID: "externalKey:secondary", Primary: false},
				},
			},
		},
	}

	data, err := json.Marshal(payload)

	require.NoError(t, err)
	require.Contains(t, string(data), `"primary":false`)
	require.Contains(t, string(data), `"orgUnitId":"externalKey:secondary","primary":false`)
}

func TestResolveWorksmobileDomainIDFromTenantIgnoresRootDomainMappings(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	rootConfig := domain.JSONMap{
		"worksmobile": map[string]any{
			"domainMappings": map[string]any{
				"samaneng.com": int64(9999),
			},
		},
	}

	got, err := ResolveWorksmobileDomainIDFromTenant(
		domain.Tenant{
			Slug:    "saman",
			Name:    "삼안",
			Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
		},
		rootConfig,
	)

	require.NoError(t, err)
	require.Equal(t, int64(1001), got)
}

func TestResolveWorksmobileDomainIDFromTenantRequiresFamilyDomainEnv(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "")

	rootConfig := domain.JSONMap{
		"worksmobile": map[string]any{
			"domainMappings": map[string]any{
				"samaneng.com": int64(9999),
			},
		},
	}

	_, err := ResolveWorksmobileDomainIDFromTenant(
		domain.Tenant{
			Slug:    "saman",
			Name:    "삼안",
			Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
		},
		rootConfig,
	)

	require.Error(t, err)
	require.Contains(t, err.Error(), "SAMAN_DOMAIN_ID")
}

func TestResolveWorksmobileDomainIDUsesEnvFamilyFallbacks(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	t.Setenv("HANMAC_DOMAIN_ID", "1002")
	t.Setenv("GPDTDC_DOMAIN_ID", "1003")
	t.Setenv("HALLA_DOMAIN_ID", "1005")
	t.Setenv("BARONGROUP_DOMAIN_ID", "1004")

	tests := []struct {
		name   string
		tenant domain.Tenant
		want   int64
	}{
		{
			name:   "saman",
			tenant: domain.Tenant{Slug: "saman", Domains: []domain.TenantDomain{{Domain: "samaneng.com"}}},
			want:   1001,
		},
		{
			name:   "hanmac",
			tenant: domain.Tenant{Slug: "hanmac", Domains: []domain.TenantDomain{{Domain: "hanmaceng.co.kr"}}},
			want:   1002,
		},
		{
			name:   "gpdtdc",
			tenant: domain.Tenant{Slug: "gpdtdc", Name: "총괄기획&기술개발센터"},
			want:   1003,
		},
		{
			name:   "halla",
			tenant: domain.Tenant{Slug: "halla", Name: "한라산업개발", Domains: []domain.TenantDomain{{Domain: "hallasanup.com"}}},
			want:   1005,
		},
		{
			name:   "hanlla legacy slug",
			tenant: domain.Tenant{Slug: "hanlla", Name: "한라산업개발"},
			want:   1005,
		},
		{
			name:   "barongroup fallback",
			tenant: domain.Tenant{Slug: "family-company", Name: "기타 가족사"},
			want:   1004,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got, err := ResolveWorksmobileDomainIDFromTenant(tt.tenant, nil)
			require.NoError(t, err)
			require.Equal(t, tt.want, got)
		})
	}
}

func TestResolveWorksmobileAccountDomainIDUsesHallaEmailDomain(t *testing.T) {
	t.Setenv("HALLA_DOMAIN_ID", "1005")
	t.Setenv("BARONGROUP_DOMAIN_ID", "1004")
	tenant := domain.Tenant{
		Slug:    "halla",
		Name:    "한라산업개발",
		Domains: []domain.TenantDomain{{Domain: "hallasanup.com"}},
	}

	got, err := ResolveWorksmobileAccountDomainIDFromEmail("user@hallasanup.com", tenant, nil)

	require.NoError(t, err)
	require.Equal(t, int64(1005), got)
}

func TestWorksmobileDomainIDsFromEnvIncludesHallaBeforeFallback(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	t.Setenv("HANMAC_DOMAIN_ID", "1002")
	t.Setenv("GPDTDC_DOMAIN_ID", "1003")
	t.Setenv("HALLA_DOMAIN_ID", "1005")
	t.Setenv("BARONGROUP_DOMAIN_ID", "1004")

	got := WorksmobileDomainIDsFromEnv()

	require.Equal(t, []int64{1001, 1002, 1003, 1005, 1004}, got)
	require.Equal(t, "한라산업개발", WorksmobileDomainLabelForID(1005))
}

func TestBuildWorksmobileUserPayloadUsesHallaDomain(t *testing.T) {
	t.Setenv("HALLA_DOMAIN_ID", "1005")
	t.Setenv("WORKS_DEFAULT_DOMAIN_HALLA", "hallasanup.com")
	tenantID := "33333333-3333-3333-3333-333333333333"
	user := domain.User{
		ID:       "44444444-4444-4444-4444-444444444444",
		Email:    "main@hallasanup.com",
		Name:     "Halla User",
		TenantID: &tenantID,
	}
	tenant := domain.Tenant{
		ID:      tenantID,
		Slug:    "halla",
		Name:    "한라산업개발",
		Domains: []domain.TenantDomain{{Domain: "hallasanup.com"}},
	}

	payload, err := BuildWorksmobileUserPayload(user, tenant, nil)

	require.NoError(t, err)
	require.Equal(t, int64(1005), payload.DomainID)
	require.Equal(t, "main@hallasanup.com", payload.Email)
}

func TestBuildWorksmobileUserPayloadAddsHanmacEmployeeAlias(t *testing.T) {
	t.Setenv("HANMAC_DOMAIN_ID", "1002")
	tenantID := "33333333-3333-3333-3333-333333333333"
	user := domain.User{
		ID:       "44444444-4444-4444-4444-444444444444",
		Email:    "main@hanmaceng.co.kr",
		Name:     "Hanmac User",
		TenantID: &tenantID,
		Metadata: domain.JSONMap{
			"employee_id":    "HM001",
			"personal_email": "private@example.com",
		},
	}
	tenant := domain.Tenant{
		ID:      tenantID,
		Slug:    "hanmac",
		Name:    "한맥",
		Domains: []domain.TenantDomain{{Domain: "hanmaceng.co.kr"}},
	}

	payload, err := BuildWorksmobileUserPayload(user, tenant, nil)

	require.NoError(t, err)
	require.Equal(t, int64(1002), payload.DomainID)
	require.Equal(t, []string{"hm001@hanmaceng.co.kr"}, payload.AliasEmails)
	require.Empty(t, payload.PrivateEmail)
	require.Equal(t, "ko_KR", payload.Locale)
}

func TestBuildWorksmobileUserPayloadAddsMultipleMetadataAliases(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	tenantID := "33333333-3333-3333-3333-333333333333"
	user := domain.User{
		ID:       "44444444-4444-4444-4444-444444444444",
		Email:    "main@samaneng.com",
		Name:     "Saman User",
		TenantID: &tenantID,
		Metadata: domain.JSONMap{
			"aliasEmails": []any{"alias1@samaneng.com", "alias2@samaneng.com", "main@samaneng.com"},
		},
	}
	tenant := domain.Tenant{
		ID:      tenantID,
		Slug:    "saman",
		Name:    "삼안",
		Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
	}

	payload, err := BuildWorksmobileUserPayload(user, tenant, nil)

	require.NoError(t, err)
	require.Equal(t, []string{"alias1@samaneng.com", "alias2@samaneng.com"}, payload.AliasEmails)
}

func TestBuildWorksmobileUserPayloadAddsSubEmailMetadataAlias(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	tenantID := "33333333-3333-3333-3333-333333333333"
	user := domain.User{
		ID:       "44444444-4444-4444-4444-444444444444",
		Email:    "main@samaneng.com",
		Name:     "Saman User",
		TenantID: &tenantID,
		Metadata: domain.JSONMap{
			"sub_email":        "alias1@hanmaceng.co.kr",
			"secondary_emails": []any{"alias2@hanmaceng.co.kr"},
		},
	}
	tenant := domain.Tenant{
		ID:      tenantID,
		Slug:    "saman",
		Name:    "삼안",
		Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
	}

	payload, err := BuildWorksmobileUserPayload(user, tenant, nil)

	require.NoError(t, err)
	require.Equal(t, []string{"alias1@hanmaceng.co.kr", "alias2@hanmaceng.co.kr"}, payload.AliasEmails)
}

func TestBuildWorksmobileUserPayloadKeepsSubEmailAliasWithPrimaryLocalPart(t *testing.T) {
	t.Setenv("SAMAN_DOMAIN_ID", "1001")
	tenantID := "33333333-3333-3333-3333-333333333333"
	user := domain.User{
		ID:       "44444444-4444-4444-4444-444444444444",
		Email:    "ypshim@samaneng.com",
		Name:     "Saman User",
		TenantID: &tenantID,
		Metadata: domain.JSONMap{
			"sub_email": "ypshim@hanmaceng.co.kr",
		},
	}
	tenant := domain.Tenant{
		ID:      tenantID,
		Slug:    "saman",
		Name:    "삼안",
		Domains: []domain.TenantDomain{{Domain: "samaneng.com"}},
	}

	payload, err := BuildWorksmobileUserPayload(user, tenant, nil)

	require.NoError(t, err)
	require.Equal(t, []string{"ypshim@hanmaceng.co.kr"}, payload.AliasEmails)
}

func TestValidateWorksmobileAliasEmailsAllowsSameLocalPartOnDifferentDomains(t *testing.T) {
	err := ValidateWorksmobileAliasEmails(
		"main@samaneng.com",
		[]string{"main@hanmaceng.co.kr"},
		map[string]string{},
	)
	require.NoError(t, err)

	err = ValidateWorksmobileAliasEmails(
		"main@samaneng.com",
		[]string{"main@samaneng.com"},
		map[string]string{},
	)
	require.Error(t, err)
	require.Contains(t, err.Error(), "duplicates")

	err = ValidateWorksmobileAliasEmails(
		"main@samaneng.com",
		[]string{"alias@hanmaceng.co.kr"},
		map[string]string{"alias@hanmaceng.co.kr": "existing-user"},
	)
	require.Error(t, err)
	require.Contains(t, err.Error(), "이미 사용 중")
}

func containsAny(value string, candidates string) bool {
	return strings.ContainsAny(value, candidates)
}

func TestWorksmobileUserStatusAction(t *testing.T) {
	require.Equal(t, WorksmobileUserActionUpsert, WorksmobileUserStatusAction(domain.UserStatusActive))
	require.Equal(t, WorksmobileUserActionUpsert, WorksmobileUserStatusAction(domain.UserStatusTemporaryLeave))
	require.Equal(t, WorksmobileUserActionSuspend, WorksmobileUserStatusAction(domain.UserStatusSuspended))
	require.Equal(t, domain.WorksmobileActionDelete, WorksmobileUserStatusAction(domain.UserStatusExtendedLeave))
	require.Equal(t, domain.WorksmobileActionDelete, WorksmobileUserStatusAction(domain.UserStatusBaronGuest))
	require.Equal(t, domain.WorksmobileActionDelete, WorksmobileUserStatusAction(domain.UserStatusArchived))
	require.Equal(t, WorksmobileUserActionUpsert, WorksmobileUserStatusAction("leave_of_absence"))
	require.Equal(t, domain.WorksmobileActionDelete, WorksmobileUserStatusAction("baron_only"))
}

func TestValidateWorksmobileExternalKeyRejectsUnsupportedCharacters(t *testing.T) {
	require.NoError(t, ValidateWorksmobileExternalKey("44444444-4444-4444-4444-444444444444"))
	require.Error(t, ValidateWorksmobileExternalKey("user/with/slash"))
	require.Error(t, ValidateWorksmobileExternalKey("user#with-hash"))
}
