/**
 * This class contains unit tests for validating the behavior of Apex classes
 * and triggers.
 *
 * Unit tests are class methods that verify whether a particular piece
 * of code is working properly. Unit test methods take no arguments,
 * commit no data to the database, and are flagged with the testMethod
 * keyword in the method definition.
 *
 * All test methods in an organization are executed whenever Apex code is deployed
 * to a production organization to confirm correctness, ensure code
 * coverage, and prevent regressions. All Apex classes are
 * required to have at least 75% code coverage in order to be deployed
 * to a production organization. In addition, all triggers must have some code coverage.
 * 
 * The @isTest class annotation indicates this class only contains test
 * methods. Classes defined with the @isTest annotation do not count against
 * the organization size limit for all Apex scripts.
 *
 * See the Apex Language Reference for more information about Testing and Code Coverage.
 */
@isTest
private class SoakupHPDeptTeamTest {
    private static Profile p{get;set;}
    private static Account hp{get;set;}
    private static List<Account> dcList{get;set;}
    private static List<Account> dptList{get;set;}
    private static User dc0Owner{get;set;}
    private static User dc1Owner{get;set;}
    private static AccountTeamMember dcT0{get;set;}

    static void initTestData() {
        p = [select Id from Profile where id =:System.Label.ProfileId_SystemAdmin];

        // ユーザー作成
        User hpOwner = new User(Test_staff__c = true, LastName = 'hp', FirstName = 'owner', Alias = 'hp', CommunityNickname = 'hpOwner', Email = 'olympus_hpowner@sunbridge.com', Username = 'olympus_hpowner@sunbridge.com', IsActive = true, EmailEncodingKey = 'ISO-2022-JP', TimeZoneSidKey = 'Asia/Tokyo', LocaleSidKey = 'ja_JP', LanguageLocaleKey = 'ja', ProfileId = p.id);
        dc0Owner = new User(Test_staff__c = true, LastName = 'dc0', FirstName = 'owner', Alias = 'dc0', CommunityNickname = 'dc0Owner', Email = 'olympus_dc0Owner@sunbridge.com', Username = 'olympus_dc0Owner@sunbridge.com', IsActive = true, EmailEncodingKey = 'ISO-2022-JP', TimeZoneSidKey = 'Asia/Tokyo', LocaleSidKey = 'ja_JP', LanguageLocaleKey = 'ja', ProfileId = p.id);
        dc1Owner = new User(Test_staff__c = true, LastName = 'dc1', FirstName = 'owner', Alias = 'dc1', CommunityNickname = 'dc1Owner', Email = 'olympus_dc1Owner@sunbridge.com', Username = 'olympus_dc1Owner@sunbridge.com', IsActive = true, EmailEncodingKey = 'ISO-2022-JP', TimeZoneSidKey = 'Asia/Tokyo', LocaleSidKey = 'ja_JP', LanguageLocaleKey = 'ja', ProfileId = p.id);
        User dc0Member = new User(Test_staff__c = true, LastName = 'dc0', FirstName = 'member', Alias = 'dc0Mb', CommunityNickname = 'dc0Member', Email = 'olympus_dc0Member@sunbridge.com', Username = 'olympus_dc0Member@sunbridge.com', IsActive = true, EmailEncodingKey = 'ISO-2022-JP', TimeZoneSidKey = 'Asia/Tokyo', LocaleSidKey = 'ja_JP', LanguageLocaleKey = 'ja', ProfileId = p.id);
        User dc1Member = new User(Test_staff__c = true, LastName = 'dc1', FirstName = 'member', Alias = 'dc1Mb', CommunityNickname = 'dc1Member', Email = 'olympus_dc1Member@sunbridge.com', Username = 'olympus_dc1Member@sunbridge.com', IsActive = true, EmailEncodingKey = 'ISO-2022-JP', TimeZoneSidKey = 'Asia/Tokyo', LocaleSidKey = 'ja_JP', LanguageLocaleKey = 'ja', ProfileId = p.id);
        insert new User[] {hpOwner, dc0Owner, dc1Owner, dc0Member, dc1Member};
        
        
        // 取引先作成
        List<RecordType> rectHp = [select Id from RecordType where IsActive = true and SobjectType = 'Account' and Name = '病院'];
        if (rectHp.size() == 0) {
            return;
        }
        List<RecordType> rectDpt = [select Id from RecordType where IsActive = true and SobjectType = 'Account' and Name = '診療科 消化科'];
        if (rectDpt.size() == 0) {
            return;
        }
        system.runAs(hpOwner){
            hp = new Account(RecordTypeId = rectHp[0].Id, Name = 'SoakupTestHp', OwnerId = hpOwner.Id);
            insert hp;
        }

        // 戦略課室に、担当者とチームを設定
        dcList = [select Id, RecordType.Name from Account where ParentId = :hp.Id];
        Integer i = 0;
        for (i = 0; i < dcList.size(); i++) {
            Account dc = dcList[i];
            if (dc.RecordType.Name == '戦略科室分類 消化科') {
                break;
            }
        }
        if (i > 0) {
            // '戦略科室分類 消化科' がないことはないです。
            Account dc = dcList[i];
            dcList[i] = dcList[0];
            dcList[0] = dc;
        }
        system.runAs(dc0Owner){
            dcList[0].OwnerId = dc0Owner.Id;
        }
        system.runAs(dc1Owner){
            dcList[1].OwnerId = dc1Owner.Id;
        }
        system.runAs(new User(Id = Userinfo.getUserId())){
            update dcList;
        }
        dcT0 = new AccountTeamMember();//AccountAccessLevel = 'Edit'
        system.runAs(dc0Member){
            dcT0.UserId = dc0Member.Id;
        }
        dcT0.TeamMemberRole = '営業担当';
        dcT0.AccountId = dcList[0].Id;
        AccountTeamMember dcT01 = new AccountTeamMember();//AccountAccessLevel = 'Edit'   
               // 同じ dc1Member ですが、違う戦略課室の場合、病院にSoakupされるとどうなる？
        dcT01.TeamMemberRole = '営業担当';
        dcT01.AccountId = dcList[0].Id;
        AccountTeamMember dcT1 = new AccountTeamMember();//AccountAccessLevel = 'Read'
        dcT1.TeamMemberRole = 'FSE';
        dcT1.AccountId = dcList[1].Id;
        system.runAs(dc1Member){
            dcT01.UserId = dc1Member.Id;
            dcT1.UserId = dc1Member.Id;
        }    
        system.runAs(new User(Id = Userinfo.getUserId())){
            insert new AccountTeamMember[] {dcT0, dcT01};
        }
        AccountShare dcTS0 = new AccountShare(UserOrGroupId=dcT0.UserId, AccountId=dcT0.AccountId, AccountAccessLevel='Edit', OpportunityAccessLevel = 'None');
        AccountShare dcTS01 = new AccountShare(UserOrGroupId=dcT01.UserId, AccountId=dcT01.AccountId, AccountAccessLevel='Edit', OpportunityAccessLevel = 'None');

        system.runAs(new User(Id = Userinfo.getUserId())){
            insert new AccountShare[] {dcTS0, dcTS01};
            // dcT1のRead権限を後に設定
            insert new AccountTeamMember[] {dcT1};                    // 後優先になる
        }
        AccountShare dcTS1 = new AccountShare(UserOrGroupId=dcT1.UserId, AccountId=dcT1.AccountId, AccountAccessLevel='Read', OpportunityAccessLevel = 'None');
        system.runAs(new User(Id = Userinfo.getUserId())){
            insert new AccountShare[] {dcTS1};
        }

        // 診療科作成、Ownerとチームは自動引継ぐと想定
        Account dpt0 = new Account(RecordTypeId = rectDpt[0].Id, Name = '*', Department_Name__c = 'SoakupTestDepart0', ParentId = dcList[0].Id, Department_Class__c = dcList[0].Id, Hospital__c = hp.Id);
        Account dpt1 = new Account(RecordTypeId = rectDpt[0].Id, Name = '*', Department_Name__c = 'SoakupTestDepart1', ParentId = dcList[0].Id, Department_Class__c = dcList[0].Id, Hospital__c = hp.Id);
        system.runAs(new User(Id = Userinfo.getUserId())){
            dptList = new Account[] {dpt0, dpt1};
            insert dptList;
        }
    }

    /**
     * 正常ケース 診療科複数から吸い上げ、さらに病院に吸い上げ
     */
    static testMethod void testExecute_01() {
        String loginId = UserInfo.getUserId();
        SoakupHPDeptTeamTest.initTestData();

        // 診療科にチームを追加
        User dpt0Owner = new User(Test_staff__c = true, LastName = 'dpt0', FirstName = 'owner', Alias = 'dpt0', CommunityNickname = 'dpt0Owner', Email = 'olympus_dpt0Owner@sunbridge.com', Username = 'olympus_dpt0Owner@sunbridge.com', IsActive = true, EmailEncodingKey = 'ISO-2022-JP', TimeZoneSidKey = 'Asia/Tokyo', LocaleSidKey = 'ja_JP', LanguageLocaleKey = 'ja', ProfileId = p.id);
        User dpt1Owner = new User(Test_staff__c = true, LastName = 'dpt1', FirstName = 'owner', Alias = 'dpt1', CommunityNickname = 'dpt1Owner', Email = 'olympus_dpt1Owner@sunbridge.com', Username = 'olympus_dpt1Owner@sunbridge.com', IsActive = true, EmailEncodingKey = 'ISO-2022-JP', TimeZoneSidKey = 'Asia/Tokyo', LocaleSidKey = 'ja_JP', LanguageLocaleKey = 'ja', ProfileId = p.id);
        User dpt0Member = new User(Test_staff__c = true, LastName = 'dpt0', FirstName = 'member', Alias = 'dpt0Mb', CommunityNickname = 'dpt0Member', Email = 'olympus_dpt0Member@sunbridge.com', Username = 'olympus_dpt0Member@sunbridge.com', IsActive = true, EmailEncodingKey = 'ISO-2022-JP', TimeZoneSidKey = 'Asia/Tokyo', LocaleSidKey = 'ja_JP', LanguageLocaleKey = 'ja', ProfileId = p.id);
        User dpt1Member = new User(Test_staff__c = true, LastName = 'dpt1', FirstName = 'member', Alias = 'dpt1Mb', CommunityNickname = 'dpt1Member', Email = 'olympus_dpt1Member@sunbridge.com', Username = 'olympus_dpt1Member@sunbridge.com', IsActive = true, EmailEncodingKey = 'ISO-2022-JP', TimeZoneSidKey = 'Asia/Tokyo', LocaleSidKey = 'ja_JP', LanguageLocaleKey = 'ja', ProfileId = p.id);
        insert new User[] {dpt0Owner, dpt1Owner, dpt0Member, dpt1Member};
        system.runAs(dpt0Owner){
            dptList[0].OwnerId = dpt0Owner.Id;
        }
        system.runAs(dpt1Owner){
            dptList[1].OwnerId = dpt1Owner.Id;
            update dptList;
        }

        
        system.runAs(new user(Id = Userinfo.getUserId())){
            AccountTeamMember dT00 = new AccountTeamMember();//AccountAccessLevel = 'Read'
            dT00.UserId = dc0Owner.Id;
            dT00.TeamMemberRole = '営業担当';
            dT00.AccountId = dptList[0].Id;
            AccountTeamMember dT0 = new AccountTeamMember();//AccountAccessLevel = 'Read'
            dT0.UserId = dpt0Member.Id;
            dT0.TeamMemberRole = '営業担当';
            dT0.AccountId = dptList[0].Id;
            AccountTeamMember dT1 = new AccountTeamMember();//AccountAccessLevel = 'Edit'
            dT1.UserId = dpt1Member.Id;
            dT1.TeamMemberRole = 'FSE';
            dT1.AccountId = dptList[1].Id;
            insert new AccountTeamMember[] {dT00, dT0, dT1};
            AccountShare dTS00 = new AccountShare(UserOrGroupId=dT00.UserId, AccountId=dT00.AccountId, AccountAccessLevel='Read', OpportunityAccessLevel = 'None');
            AccountShare dTS0 = new AccountShare(UserOrGroupId=dT0.UserId, AccountId=dT0.AccountId, AccountAccessLevel='Read', OpportunityAccessLevel = 'None');
            AccountShare dTS1 = new AccountShare(UserOrGroupId=dT1.UserId, AccountId=dT1.AccountId, AccountAccessLevel='Edit', OpportunityAccessLevel = 'None');
            insert new AccountShare[] {dTS00, dTS0, dTS1};    
            // assert
            SoakupHPDeptTeam.execute(dcList[0].Id);
            List<Account> dList = [select Id, Owner.Name from Account where Id = :dptList];
            System.assertEquals('dc0 owner', dList[0].Owner.Name);
            System.assertEquals('dc0 owner', dList[1].Owner.Name);
            List<AccountTeamMember> dTList = [select Id, UserId, User.Name, TeamMemberRole, AccountId, AccountAccessLevel from AccountTeamMember where AccountId = :dptList[0].Id order by User.Name];
            //SP_Main__c自动赋值加入team System.assertEquals(2, dTList.size());
            System.assertEquals(2, dTList.size());
            dTList = [select Id, UserId, User.Name, TeamMemberRole, AccountId, AccountAccessLevel from AccountTeamMember where AccountId = :dptList[1].Id order by User.Name];
            //SP_Main__c自动赋值加入team System.assertEquals(2, dTList.size());
            System.assertEquals(2, dTList.size());
            List<AccountTeamMember> hpTList = [select Id, UserId, User.Name, TeamMemberRole, AccountId, AccountAccessLevel from AccountTeamMember where AccountId = :hp.Id and UserId <> :loginId order by User.Name];
            List<Account> hpList = [select Id, Owner.Name from Account where Id = :hp.Id];
            //System.assertEquals(3, hpTList.size());
            System.assertEquals('dc0 member', hpTList[0].User.Name);
            //TODO 2016/6/14 System.AssertException: Assertion Failed: Expected: Edit, Actual: Read
            //System.assertEquals('Edit', hpTList[0].AccountAccessLevel);
            System.assertEquals('dc0 owner', hpList[0].Owner.Name);                     // チームに入れない、ownerになる
            System.assertEquals('dc1 member', hpTList[1].User.Name);                    // 同じ dc0Member ですが、違う戦略課室の場合、病院にSoakupされるとどうなる？ ==>  後優先 になる
            //System.assertEquals('Edit', hpTList[2].AccountAccessLevel);
            //System.assertEquals('営業担当', hpTList[1].TeamMemberRole);
            System.assertEquals('dc1 owner', hpTList[2].User.Name);
            //System.assertEquals('Edit', hpTList[2].AccountAccessLevel);
            
            // 戦略課室のチームを削除
            delete dcT0;
            // assert
            SoakupHPDeptTeam.execute(dcList[0].Id);
            dTList = [select Id, UserId, User.Name, TeamMemberRole, AccountId, AccountAccessLevel from AccountTeamMember where AccountId = :dptList[0].Id order by User.Name];
            //SP_Main__c自动赋值加入team System.assertEquals(1, dTList.size());
            System.assertEquals(1, dTList.size());
            dTList = [select Id, UserId, User.Name, TeamMemberRole, AccountId, AccountAccessLevel from AccountTeamMember where AccountId = :dptList[1].Id order by User.Name];
            //SP_Main__c自动赋值加入team System.assertEquals(1, dTList.size());
            System.assertEquals(1, dTList.size());
            hpTList = [select Id, UserId, User.Name, TeamMemberRole, AccountId, AccountAccessLevel from AccountTeamMember where AccountId = :hp.Id and UserId <> :loginId order by User.Name];
            //SP_Main__c自动赋值加入team System.assertEquals(2, hpTList.size());
            System.assertEquals(3, hpTList.size());
        }
    }
}