@isTest
private class UserProfileHandlerTest {

    @isTest
    static void futureInsertGroupMember() {
        // 新建 Group
        Group insertGroup = new Group(
            Name = 'UserProfileHandlerTest_G1_' + System.now().getTime()
        );
        insert insertGroup;

        Test.startTest();
        UserProfileHandler.futureInsertGroupMember('{"' + insertGroup.Id + '": "' + UserInfo.getUserId() + '"}');
        Test.stopTest();

        Group g1 = [SELECT Id, Name FROM Group WHERE Type = 'Regular' AND Name LIKE 'UserProfileHandlerTest_G1_%'];
        System.assert(g1.Name.startsWith('UserProfileHandlerTest_G1_'));

        GroupMember gm1 = [SELECT Id, UserOrGroupId FROM GroupMember WHERE GroupId =: g1.Id];
        System.assertEquals(UserInfo.getUserId(), gm1.UserOrGroupId);
    }

    /**
     * new User x 4 with Group(既存) x 2
     */
    @isTest
    static void dynamicUpdateGroup_CreateUser() {
        // 做数据
        setupAccount(new List<String> {'备品共享_其他_备品管理中心', '备品共享_上海_华东营业本部'});

        Map<String, Group> findGroupNameMap = new Map<String, Group>();
        for (Group grp : [SELECT Id, Name FROM Group WHERE Type = 'Regular' AND Name LIKE '备品共享_%']) {
            findGroupNameMap.put(grp.Name, grp);
        }
        List<Group> grpList = new List<Group>();
        Group g1 = findGroupNameMap.get('备品共享_其他_备品管理中心');
        if (null == g1) {
            g1 = new Group(Name = '备品共享_其他_备品管理中心');
            grpList.add(g1);
        }
        Group g2 = findGroupNameMap.get('备品共享_上海_华东营业本部');
        if (null == g2) {
            g2 = new Group(Name = '备品共享_上海_华东营业本部');
            grpList.add(g2);
        }
        insert grpList;

        Test.startTest();
        UserProfileHandler.testTargetDepts = new Set<String> {'医疗备品管理中心', '医疗华东营业本部'};
        List<User> g1_Users = setupUsers('G1', '其他', '医疗备品管理中心');
        List<User> g2_Users = setupUsers('G2', '上海', '医疗华东营业本部');
        Test.stopTest();

        List<GroupMember> g1Members = [SELECT Id, UserOrGroupId FROM GroupMember WHERE GroupId =: g1.Id ORDER BY UserOrGroupId];
        List<GroupMember> g2Members = [SELECT Id, UserOrGroupId FROM GroupMember WHERE GroupId =: g2.Id ORDER BY UserOrGroupId];
        System.assertEquals(2, g1Members.size());
        //System.assertEquals(2, g2Members.size());
        System.assertEquals(g1_Users[0].Id, g1Members[0].UserOrGroupId);
        System.assertEquals(g1_Users[1].Id, g1Members[1].UserOrGroupId);
        //System.assertEquals(g2_Users[0].Id, g2Members[0].UserOrGroupId);
        //System.assertEquals(g2_Users[1].Id, g2Members[1].UserOrGroupId);
    }

    /**
     * new User x 4, new Group x 2
     */
    @isTest
    static void dynamicUpdateGroup_CreateGroupCreateUser() {
        // 做数据
        setupAccount(new List<String> {'备品共享_其他_CreateGroup1', '备品共享_其他_CreateGroup2'});

        Test.startTest();
        UserProfileHandler.testTargetDepts = new Set<String> {'CreateGroup1', 'CreateGroup2'};
        List<User> g1_Users = setupUsers('G1', '其他', 'CreateGroup1');
        List<User> g2_Users = setupUsers('G2', '其他', 'CreateGroup2');
        Test.stopTest();

        List<Group> gList = [SELECT Id, Name FROM Group WHERE Type = 'Regular' AND Name LIKE '备品共享_其他_%' ORDER BY Name];
        System.assertEquals(2, gList.size());
        System.assertEquals('备品共享_其他_CreateGroup1', gList[0].Name);
        System.assertEquals('备品共享_其他_CreateGroup2', gList[1].Name);

        List<GroupMember> gMembers = [SELECT Id, UserOrGroupId FROM GroupMember WHERE GroupId IN: gList ORDER BY GroupId, UserOrGroupId];
        System.assertEquals(4, gMembers.size());
        System.assertEquals(g1_Users[0].Id, gMembers[0].UserOrGroupId);
        System.assertEquals(g1_Users[1].Id, gMembers[1].UserOrGroupId);
        System.assertEquals(g2_Users[0].Id, gMembers[2].UserOrGroupId);
        System.assertEquals(g2_Users[1].Id, gMembers[3].UserOrGroupId);
    }

    /**
     * update User x 4 with Group(既存) x 2 to new Group x 2
     */
    @isTest
    static void dynamicUpdateGroup_ChangeGroup() {
        // 做数据 like #dynamicUpdateGroup_CreateUser()
        setupAccount(new List<String> {'备品共享_其他_备品管理中心', '备品共享_上海_华东营业本部', '备品共享_其他_CreateGroup1', '备品共享_上海_CreateGroup2'});
        Map<String, Group> findGroupNameMap = new Map<String, Group>();
        for (Group grp : [SELECT Id, Name FROM Group WHERE Type = 'Regular' AND Name LIKE '备品共享_%']) {
            findGroupNameMap.put(grp.Name, grp);
        }
        List<Group> grpList = new List<Group>();
        Group g1 = findGroupNameMap.get('备品共享_其他_备品管理中心');
        if (null == g1) {
            g1 = new Group(Name = '备品共享_其他_备品管理中心');
            grpList.add(g1);
        }
        Group g2 = findGroupNameMap.get('备品共享_上海_华东营业本部');
        if (null == g2) {
            g2 = new Group(Name = '备品共享_上海_华东营业本部');
            grpList.add(g2);
        }
        insert grpList;

        UserProfileHandler.testTargetDepts = new Set<String> {'医疗备品管理中心', '医疗华东营业本部'};
        List<User> g1_Users = setupUsers('G1', '其他', '医疗备品管理中心');
        List<User> g2_Users = setupUsers('G2', '上海', '医疗华东营业本部');

        // 做数据 的 assert
        List<GroupMember> g1Members = [SELECT Id, UserOrGroupId FROM GroupMember WHERE GroupId =: g1.Id ORDER BY UserOrGroupId];
        List<GroupMember> g2Members = [SELECT Id, UserOrGroupId FROM GroupMember WHERE GroupId =: g2.Id ORDER BY UserOrGroupId];
        System.assertEquals(2, g1Members.size());
        //System.assertEquals(2, g2Members.size());
        System.assertEquals(g1_Users[0].Id, g1Members[0].UserOrGroupId);
        System.assertEquals(g1_Users[1].Id, g1Members[1].UserOrGroupId);
       // System.assertEquals(g2_Users[0].Id, g2Members[0].UserOrGroupId);
        //System.assertEquals(g2_Users[1].Id, g2Members[1].UserOrGroupId);

        Test.startTest();
        UserProfileHandler.testTargetDepts = new Set<String> {'CreateGroup1', 'CreateGroup2'};
        g1_Users[0].Dept__c = 'CreateGroup1';
        g1_Users[1].Dept__c = 'CreateGroup1';
        g2_Users[0].Dept__c = 'CreateGroup2';
        g2_Users[1].Dept__c = 'CreateGroup2';
        List<User> updUserList = new List<User>();
        updUserList.addAll(g1_Users);
        updUserList.addAll(g2_Users);
        update updUserList;
        Test.stopTest();

        // Delete 的 assert
        g1Members = [SELECT Id, UserOrGroupId FROM GroupMember WHERE GroupId =: g1.Id];
        g2Members = [SELECT Id, UserOrGroupId FROM GroupMember WHERE GroupId =: g2.Id];
        System.assertEquals(0, g1Members.size());
        //System.assertEquals(0, g2Members.size());

        // Insert 的 assert
        List<Group> gList = [SELECT Id, Name FROM Group WHERE Type = 'Regular' AND Name LIKE '%_CreateGroup%' ORDER BY Name];
        List<GroupMember> gMembers = [SELECT Id, UserOrGroupId FROM GroupMember WHERE GroupId IN: gList ORDER BY GroupId, UserOrGroupId];

        System.assertEquals(2, gList.size(), gList);
        System.assertEquals('备品共享_上海_CreateGroup2', gList[0].Name);
        System.assertEquals('备品共享_其他_CreateGroup1', gList[1].Name);

        System.assertEquals(4, gMembers.size());
        System.assertEquals(g1_Users[0].Id, gMembers[0].UserOrGroupId);
        System.assertEquals(g1_Users[1].Id, gMembers[1].UserOrGroupId);
        System.assertEquals(g2_Users[0].Id, gMembers[2].UserOrGroupId);
        System.assertEquals(g2_Users[1].Id, gMembers[3].UserOrGroupId);
    }

    /**
     * update User x 2 with Group(既存) x 1 --> User.IsActive = false --> IsActive = true
     */
    @isTest
    static void dynamicUpdateGroup_UserActive() {
        // 做数据 like #dynamicUpdateGroup_CreateUser()
        setupAccount(new List<String> {'备品共享_其他_备品管理中心', '备品共享_上海_华东营业本部', '备品共享_其他_CreateGroup1', '备品共享_上海_CreateGroup2'});
        Map<String, Group> findGroupNameMap = new Map<String, Group>();
        for (Group grp : [SELECT Id, Name FROM Group WHERE Type = 'Regular' AND Name LIKE '备品共享_%']) {
            findGroupNameMap.put(grp.Name, grp);
        }
        List<Group> grpList = new List<Group>();
        Group g1 = findGroupNameMap.get('备品共享_其他_备品管理中心');
        if (null == g1) {
            g1 = new Group(Name = '备品共享_其他_备品管理中心');
            grpList.add(g1);
        }
        Group g2 = findGroupNameMap.get('备品共享_上海_华东营业本部');
        if (null == g2) {
            g2 = new Group(Name = '备品共享_上海_华东营业本部');
            grpList.add(g2);
        }
        insert grpList;

        UserProfileHandler.testTargetDepts = new Set<String> {'医疗备品管理中心', '医疗华东营业本部'};
        List<User> g1_Users = setupUsers('G1', '其他', '医疗备品管理中心');
        List<User> g2_Users = setupUsers('G2', '上海', '医疗华东营业本部');

        // 做数据 的 assert
        List<GroupMember> g1Members = [SELECT Id, UserOrGroupId FROM GroupMember WHERE GroupId =: g1.Id ORDER BY UserOrGroupId];
        List<GroupMember> g2Members = [SELECT Id, UserOrGroupId FROM GroupMember WHERE GroupId =: g2.Id ORDER BY UserOrGroupId];
        System.assertEquals(2, g1Members.size());
       // System.assertEquals(2, g2Members.size());
        System.assertEquals(g1_Users[0].Id, g1Members[0].UserOrGroupId);
        System.assertEquals(g1_Users[1].Id, g1Members[1].UserOrGroupId);
        //System.assertEquals(g2_Users[0].Id, g2Members[0].UserOrGroupId);
        //System.assertEquals(g2_Users[1].Id, g2Members[1].UserOrGroupId);

        // User.IsActive = false
        g1_Users[0].IsActive = false;
        update g1_Users;
        g1Members = [SELECT Id, UserOrGroupId FROM GroupMember WHERE GroupId =: g1.Id AND UserOrGroupId =: g1_Users[0].Id];
        System.assertEquals(1, g1Members.size());
        System.assertEquals(g1_Users[0].Id, g1Members[0].UserOrGroupId);
        Delete g1Members;

        Test.startTest();
        // User.IsActive = true
        g1_Users[0].IsActive = true;
        update g1_Users;
        Test.stopTest();

        g1Members = [SELECT Id, UserOrGroupId FROM GroupMember WHERE GroupId =: g1.Id AND UserOrGroupId =: g1_Users[0].Id];
        System.assertEquals(1, g1Members.size());
        System.assertEquals(g1_Users[0].Id, g1Members[0].UserOrGroupId);
    }

    private static List<User> setupUsers(String gNo, String province, String dept) {
        Long nowTimeLong = System.now().getTime();
        List<User> insertUsers = new List<User>();
        User g1_u1 = New User(
            Email = gNo + '_U1@testorg.com',
            UserName = gNo + '_U1@testorg.com' + nowTimeLong,
            Alias = gNo + '_U1',
            LastName = gNo,
            Firstname = 'U1',
            Work_Location__c = province,
            Dept__c = dept,
            ProfileId = System.Label.ProfileId_SystemAdmin,
            TimeZoneSidKey='Asia/Shanghai',
            EmailEncodingKey='UTF-8',
            LanguageLocaleKey='zh_CN',
            LocaleSidKey='zh_CN'
        );
        insertUsers.add(g1_u1);
        User g1_u2 = New User(
            Email = gNo + '_U2@testorg.com',
            UserName = gNo + '_U2@testorg.com' + nowTimeLong,
            Alias = gNo + '_U2',
            LastName = gNo,
            Firstname = 'U2',
            Work_Location__c = province,
            Dept__c = dept,
            ProfileId = System.Label.ProfileId_SystemAdmin,
            TimeZoneSidKey='Asia/Shanghai',
            EmailEncodingKey='UTF-8',
            LanguageLocaleKey='zh_CN',
            LocaleSidKey='zh_CN'
        );
        insertUsers.add(g1_u2);

        insert insertUsers;
        return insertUsers;
    }

    private static void setupAccount(List<String> othList) {
        StaticParameter.EscapeAccountTrigger = true;

        System.runAs(new User(Id = Userinfo.getUserId())) {
            // 省
            Address_Level__c al1 = new Address_Level__c();
            al1.Name = '東京';
            al1.Level1_Code__c = 'CN-99';
            al1.Level1_Sys_No__c = '999999';
            insert al1;
            // 市
            Address_Level2__c al2 = new Address_Level2__c();
            al2.Level1_Code__c = 'CN-99';
            al2.Level1_Sys_No__c = '999999';
            al2.Level1_Name__c = '東京';
            al2.Name = '渋谷区';
            al2.Level2_Code__c = 'CN-9999';
            al2.Level2_Sys_No__c = '9999999';
            al2.Address_Level__c = al1.id;
            insert al2;

            // Olympus社内 9999999
            Account hospital = new Account();
            hospital.recordtypeId = [Select Id FROM RecordType WHERE IsActive = true and SobjectType = 'Account' and DeveloperName = 'HP'].id;
            hospital.Name = 'Olympus社内';
            hospital.AgentCode_Ext__c = System.Label.Account_Asset_Hospatal;
            hospital.Is_Active__c = '有効';
            hospital.Attribute_Type__c = '其他';
            hospital.Speciality_Type__c = 'その他';
            hospital.Grade__c = '一般';
            hospital.OCM_Category__c = 'L';
            hospital.Is_Medical__c = '非医疗机构';
            hospital.State_Master__c = al1.id;
            hospital.City_Master__c = al2.id;
            hospital.Town__c = '东京';
            insert hospital;

            // 戦略科室を得る
            Account strategicDep = new Account();
            strategicDep.recordtypeId = [Select Id FROM RecordType WHERE IsActive = true and SobjectType = 'Account' and DeveloperName = 'Department_Class_OTH'].id;
            strategicDep.Name = 'Olympus社内 其他';
            strategicDep.Department_Class_Label__c = '其他';
            strategicDep.Hospital__c = hospital.Id;
            strategicDep.ParentId = hospital.Id;
            insert strategicDep;

            // 备品中心:9999998
            List<Account> departmentList = new List<Account>();
            Account accountDep = new Account();
            accountDep.recordtypeId = [Select Id FROM RecordType WHERE IsActive = true and SobjectType = 'Account' and DeveloperName = 'Department_OTH'].id;
            accountDep.Name = 'Olympus社内 其他 备品';
            accountDep.AgentCode_Ext__c = System.Label.Account_Asset;
            accountDep.ParentId = strategicDep.Id;
            accountDep.Department_Class__c = strategicDep.Id;
            accountDep.Department_Name__c = '备品';
            accountDep.Hospital__c = hospital.Id;
            departmentList.add(accountDep);

            for (String dptName : othList) {
                Account accountOth = new Account(
                    recordtypeId = accountDep.recordtypeId,
                    Name = 'Olympus社内 其他 ' + dptName,
                    ParentId = strategicDep.Id,
                    Department_Class__c = strategicDep.Id,
                    Department_Name__c = dptName,
                    Hospital__c = hospital.Id
                );
                departmentList.add(accountOth);
            }
            insert departmentList;
        }
    }
}