public with sharing class ConsumApplySplitController {

    /*--------- private ---------*/
    private Id objId {get; set;}            // 申请单ID
    private String raesIds {get; set;}      // 被选中的一览记录Id

    /*--------- public(画面表示用) ---------*/
    public Consum_Apply__c ra {get; private set;}   // objId的源申请单
    public List<Consum_Apply_Equipment_Set__c> raesList {get; set;}   // 符合分单条件的被选中的一览记录
    public String saveStatus {get; set;}                              // 分单结果： 'ok'--成功
    public String errorMessage;
    public Consum_Apply__c cloneRas {get; set;}                       // 分单后新建的申请单

    /**
    * @description ConsumApplySplitController Class的构造函数
    * @param objId   申请单ID
    * @param raesIds 被选中的一览记录Id
    **/
    public ConsumApplySplitController() {
        this.objId = ApexPages.currentPage().getParameters().get('objId');
        this.raesIds = ApexPages.currentPage().getParameters().get('raesIds');
    }

    /**
    * @description ConsumApplySplitController 初始化方法
    **/
    public void init() {

        try{
            if (String.isBlank(this.objId)) {
                throw new ControllerUtil.myException('请设置耗材申请的Id');
            }
            if (String.isBlank(this.raesIds)) {
                throw new ControllerUtil.myException('请设置耗材申请一览的Id');
            }
            // 1.判断是否存在页面传过来Id对应的申请单记录 & 状态和Id都符合的选中一览记录
            List<Consum_Apply__c> raList = getRa();
            if (raList.size() == 0) {
                throw new ControllerUtil.myException('没有检索出耗材申请');
            }
            this.ra = raList[0];

            // 2.新建申请单，选中的一览记录转移到新的申请单
            this.cloneRas = ra.clone();

            // 3.判断当前申请单&选中一览是否符合分单条件
            checkRAES(true);

            // 分单页面分单理由初始为空
            this.cloneRas.Split_Apply_Reason__c = null;

        } catch (ControllerUtil.myException me) {
            System.debug('myException caught when init: ' + me.getMessage());
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, me.getMessage()));
            errorMessage = me.getStackTraceString();
            return;
        } catch (Exception e) {
            System.debug('Exception caught when init: ' + e.getStackTraceString());
            ApexPages.addMessages(e);
            errorMessage = e.getStackTraceString();
            return;
        }
    }

    /**
    * @description 保存分单理由
    **/
    public void saveSplit() {
        Savepoint sp = Database.setSavepoint();
        try {
            List<Consum_Apply__c> lockRaList = [
                    select Id, Name
                    from Consum_Apply__c
                    where Id  = :ra.Id
                    for update];

            if (lockRaList.size() <> 1) {
                throw new ControllerUtil.myException('源数据('+ ra.Name +') 已经被其他用户操作，请重试');
            }

            // 保存前再次判断当前申请单&选中一览是否符合分单条件
            String rootRaId = checkRAES(true);

            String statusMessage = addAndUpdate(rootRaId);
            if (statusMessage != '1') {
                throw new ControllerUtil.myException(statusMessage);
            }
            saveStatus = 'ok';

        } catch (ControllerUtil.myException me) {
            Database.rollback(sp);
            System.debug('myException caught when save: ' + me.getMessage());
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, me.getMessage()));
            saveStatus = 'ng';
            errorMessage = me.getStackTraceString();
        } catch (DmlException de) {
            Database.rollback(sp);
            System.debug('DmlException caught when save: ' + de.getMessage());
            ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, de.getMessage()));
            saveStatus = 'ng';
            errorMessage = de.getStackTraceString();
        } catch (Exception e) {
            Database.rollback(sp);
            System.debug('Exception caught when save: ' + e.getStackTraceString());
            ApexPages.addMessages(e);
            saveStatus = 'ng';
            errorMessage = e.getStackTraceString();
        }
    }

    /**
    * 选中一览记录是否符合分单条件判断
    * @param throwErrorFlg
    * @return 最原始申请单Id
    **/
    private String checkRAES(Boolean throwErrorFlg) {

        // 判断是否存在状态和Id和父申请单都符合的选中一览记录
        String[] ids = raesIds.split(',');

        // 分单条件之一览状态--'待分配', '排队中', '暂定分配', '已分配', '已出库指示', '已下架', '出库前已检测'
        Set<String> statusRaesSet = new Set<String>{Consum_ApplyUtil.CaesStatusMap.get(Consum_ApplyUtil.CaesStatus.Dai_Fen_Pei.ordinal()),
                Consum_ApplyUtil.CaesStatusMap.get(Consum_ApplyUtil.CaesStatus.Pai_Dui_Zhong.ordinal()),
                Consum_ApplyUtil.CaesStatusMap.get(Consum_ApplyUtil.CaesStatus.Zan_Ding_Fen_Pei.ordinal()),
                Consum_ApplyUtil.CaesStatusMap.get(Consum_ApplyUtil.CaesStatus.Yi_Fen_Pei.ordinal()),
                Consum_ApplyUtil.CaesStatusMap.get(Consum_ApplyUtil.CaesStatus.Yi_Chu_Ku_Zhi_Shi.ordinal()),
                Consum_ApplyUtil.CaesStatusMap.get(Consum_ApplyUtil.CaesStatus.Yi_Xia_Jia.ordinal()),
                Consum_ApplyUtil.CaesStatusMap.get(Consum_ApplyUtil.CaesStatus.Chu_Ku_Qian_Yi_Jian_Ce.ordinal())};

        this.raesList = [
                SELECT Id
                     , Name
                     , RAES_Status__c
                     //, Loaner_code_F__c
                     , Consum_Apply__c
                     , Old_Consum_Apply__c
                     , Model_No__c
                FROM Consum_Apply_Equipment_Set__c
                WHERE Id in :ids
                AND Consum_Apply__c = :this.objId
                AND RAES_Status__c in :statusRaesSet];

        // 防止对一条一览进行多次分单，有可能分单后源申请单页面未刷新
        for (Consum_Apply_Equipment_Set__c raes : this.raesList) {
            if (throwErrorFlg && raes.Consum_Apply__c != this.objId) {
                throw new ControllerUtil.myException('已选一览已被分到其他申请单');
            }
        }

        if (throwErrorFlg && raesList.size() != ids.size()) {
            throw new ControllerUtil.myException('已选一览状态不符合分单条件');
        }

        // rootRaId: 最原始申请单Id
        String rootRaId = raesList[0].Old_Consum_Apply__c;
        if (String.isBlank(raesList[0].Old_Consum_Apply__c)) {
            rootRaId = raesList[0].Consum_Apply__c;
        }

        // RentalApplyEquipmentSetHandler handler = new RentalApplyEquipmentSetHandler();
        Set<String> raIds = new Set<String>{this.objId};
        Set<String> emptyRaObjs = ConsumApplyEquipmentSetHandler.checkConsumApplyNotExistRAES(raesList, raIds); // raesList为页面选中一览
        if (emptyRaObjs.size() != 0) {
            throw new ControllerUtil.myException('这个申请单下必须要有一条借出备品一览,不能分单了');
        }

        return rootRaId;
    }

    /**
    * @description 新建申请单，更改选中一览与申请单的联系
    * @param rootRaId 最原始申请单Id
    * @return String 操作成功返回‘1’，失败返回message
    */
    private String addAndUpdate(String rootRaId) {
        // 1.获取rootRaList[0] -- 当前申请单对应的最原始的申请单
        List<Consum_Apply__c> rootRaList = [
                select Id, Name
                from Consum_Apply__c
                where Id = :rootRaId];

        if (rootRaList.size() == 0) {
            throw new ControllerUtil.myException('最原始申请单('+ ra.Name +') 已经不存在，请确认数据。');
        }

        // 分单出来的个数
        List<AggregateResult> oldRaList = [
                select Consum_Apply__c
                from Consum_Apply_Equipment_Set__c where Old_Consum_Apply__c = :rootRaList[0].Id
                group by Consum_Apply__c];
        Integer num = oldRaList.size() + 1;

        // 新申请单命名方式：最原始申请单_1、_2、_3…
        cloneRas.Name = rootRaList[0].Name + '_' + num;
        cloneRas.Old_Consum_Apply__c = ra.Id;                       // 源申请单Link
        // 因为有可能出库指示还没有出库的时候直接分单。所以申请书的状态字段不能变更
        // cloneRas.Status__c = Consum_ApplyUtil.CaStatusMap.get(Consum_ApplyUtil.CaStatus.Yi_Pi_Zhun.ordinal());
        FixtureUtil.withoutInsert(new Consum_Apply__c[]{cloneRas});
        //  20211105 ljh 应答沟通 update
        // cloneRas.Response__c = '\n\n耗材借出申请链接： ' + URL.getSalesforceBaseUrl().toExternalForm() + '/' + cloneRas.Id +' \n\n' + cloneRas.Response__c;
        cloneRas.Response__c = '<br/>耗材借出申请链接： ' + URL.getSalesforceBaseUrl().toExternalForm() + '/' + cloneRas.Id +' <br/><br/>' + cloneRas.Response__c;
        FixtureUtil.withoutUpdate(new Consum_Apply__c[]{cloneRas});

        // 2. 选中分单的一览与新旧申请单关联
        for (Consum_Apply_Equipment_Set__c updRaesObj : this.raesList) {
            updRaesObj.Old_Consum_Apply__c = rootRaList[0].Id;      // 最源申请单Link
            updRaesObj.Consum_Apply__c = cloneRas.Id;
        }

        // 3. 配套明细分割到新申请单，明细的Name在RentalApplyEquipmentSetDetailHandler中更新
        String[] ids = raesIds.split(',');   // 选中一览id

        List<Consum_Apply_Equipment_Set_Detail__c> raesdList = [select Id
                        , Consum_Apply_Equipment_Set__c
                        , Consum_Apply_Equipment_Set__r.Model_No__c
                    from Consum_Apply_Equipment_Set_Detail__c 
                    where Consum_Apply_Equipment_Set__c in :ids
                    ORDER BY Consum_Apply_Equipment_Set__c, Degree_Of_Importance__c];

         FixtureUtil.withoutUpdate(this.raesList);

        if (raesdList.size() != 0) {
            Integer i = 1;
            String model = '';
            for (Consum_Apply_Equipment_Set_Detail__c raesdObj : raesdList) {
                if (model != raesdObj.Consum_Apply_Equipment_Set__r.Model_No__c) {
                    model = raesdObj.Consum_Apply_Equipment_Set__r.Model_No__c;
                    i = 1;
                }
                raesdObj.Consum_Apply__c = cloneRas.Id;
                raesdObj.Degree_Of_Importance__c = i;
                i ++;
            }
            FixtureUtil.withoutUpdate(raesdList);
        }
        return '1';
    }

    /**
    * @description 获取新建申请单时需要复制的字段
    **/
    private List<Consum_Apply__c> getRa() {
       return [SELECT Id,
                    OwnerId,
                    Status__c,
                    Cancel_Reason__c,
                    Old_Consum_Apply__c,
                    Rental_Apply__c,
                    Split_Apply_Reason__c,
                    // ------ 耗材申请の詳細 ------
                    Name,                            // 申请No.
                    Salesdept__c,                    // 申请者销售本部
                    WorkPlace__c,                    // 申请者办事处
                    ApplyPerson_Phone__c,            // 申请人电话
                    Loaner_centre_mail_address__c,   // 备品中心的邮箱地址
                    Select_Status__c,                // 分配状态
                    Consum_Assistant__c,             // 备品助理
                    RA_Status__c,                    // 耗材状态
                    // OLY_OCM-504 不拷贝追加备品审批状态
                    //Add_Approval_Status__c,          // 追加备品审批状态
                    Person_In_Charge__c,             // 备品出借担当
                    applyUser__c,                    // 操作者
                    // Foul_Points__c,                  // 备品出借担当累计犯规点数
                    //First_Satisfied__c,              // 首满
                    loaner_Status__c,                // 出库状态
                    //Cross_Region_Assign__c,          // 跨区域分配
                    // ------ 备品借用方 ------
                    Hospital__c,                     // 医院
                    Strategic_dept__c,               // 战略科室
                    OCM_dept_category__c,            // 战略科室分类
                    Account__c,                      // 科室
                    OCM_segmentation__c,             // OCM分类
                    Loaner_medical_Staff__c,         // 科室负责人
                    Phone_number__c,                 // 联系电话
                    // ------ 借用备品的目的 ------
                    //Demo_purpose1__c,                // 使用目的1
                    demo_purpose2__c,                // 使用目的2
                    // OLY_OCM-669 Start
                    //Hope_Lonaer_date_Num__c,         // 希望借用天数
                    // OLY_OCM-669 End
                    Product_category__c,             // 产品分类(GI/SP)
                    Campaign__c,                     // 学会
                    OPD__c,                          // OPD报告书
                    QIS_number__c,                   // QIS
                    QIS_ID_Line__c,                  // QIS的ID值
                    Demo_purpose_text__c,            // 申请理由
                    //Repair__c,                       // 修理
                    //Follow_UP_Opp__c,                // 跟进询价1
                    //Follow_pcl_status2__c,           // 跟进询价状态
                    //Follow_pcl_status2_Text__c,      // 跟进询价状态（申请时）
                    //Shipping_Finished_Day_Func__c,   // 最终发货日(已购待货)
                    //CrinicalTrialName__c,            // 临床研究项目名称
                    //DB_loaner_request__c,            // MA本部审核合同编号
                    // ------ 备品希望借出期限 ------
                    Request_shipping_day__c,         // 希望到货日
                    //Return_dadeline_final__c,        // 最新预定归还日
                    //Request_return_day__c,           // 预定归还日
                    //Lonaer_date_not_working_date__c, // 希望借用天数
                    // ------ 发送信息 ------
                    Shipment_address__c,             // 办事处地址
                    Dealer__c,                       // 经销商
                    Loaner_received_staff__c,        // 收件者姓名 (销售或FSE)
                    Shippment_adress_detail__c,      // 发送办事处地址详细
                    direct_shippment_address__c,     // 直送发送地址
                    direct_send__c,                  // 发送方
                    pickup_time__c,                  // 自提时间
                    Loaner_received_staff_phone__c,  // 收件者电话(销售或FSE)
                    Post_Code__c,                    // 邮编
                    
                    Response__c,                     // 应答沟通
                    Request_demo_time__c,            // 申请时间
                    Request_approval_time__c,        // 批准时间（申请提交时间）
                    Request_answer_time__c,          // 备品首次分配时间
                    Application_accept_time__c,      // 应答沟通申请受理时间（回答时间）
                    OPDPlan__c,                      // OPD计划
                    // OLY_OCM-583 Start 分单时增加拷贝字段GI本部区分
                    //GI_Diff__c,                      // GI本部区分
                    Assign_Person__c,                // 分配人
                    Is_Special_Rental__c             // 是否特殊申请
                    // OLY_OCM-583 End
                 FROM Consum_Apply__c
                WHERE Id = :this.objId];
    }
}