/*
	Schedule: UpdateAgencyProductTargetSchedule
	週報の製品区分をAからBに変更したとき、A目標も対象にしないといけないため、Batch側で修正する目標は全部にしないといけないです。
	TODO 今後データ量増加により、変更差分のbatchにする仕組みを考える必要です。
 */

global class UpdateAgencyRptProductTargetBatch implements Database.Batchable<AggregateResult> {
	
	String term;
	Id rtId;
	
	global UpdateAgencyRptProductTargetBatch() {
		Date dateToday = Date.today();
        Integer year = dateToday.year();
        Integer month = dateToday.month();
        if (month < 4) {
            year -= 1;
        }

        term = String.valueOf(year - 1867) + 'P';
        rtId = [select Id,DeveloperName from RecordType where IsActive = true and SobjectType = 'Agency_Opportunity__c' and DeveloperName = 'Target'].Id;
	}

	public class AggregateResultIterator implements Iterator<AggregateResult> {
		AggregateResult [] results {get;set;}
		// tracks which result item is returned
		Integer index {get; set;}
					 
		public AggregateResultIterator(String query) {
			index = 0;
			// Fire query here to load the results
			results = Database.query(query);    
		}
		
		public boolean hasNext(){
				return results != null && !results.isEmpty() && index < results.size();
		}   
		
		public AggregateResult next(){       
				return results[index++];           
		}      
	}
	
	public class AggregateResultIterable implements Iterable<AggregateResult> {
		private String query;

		public AggregateResultIterable(String soql){
			query = soql;
		}

		public Iterator<AggregateResult> Iterator(){
			return new AggregateResultIterator(query);
		}
	}
	
	global Iterable<AggregateResult> start(Database.BatchableContext BC) {
		//String query = 'select Id, Target_Product__c, Agency_Hospital__c, Department_Cateogy__c, Product_Category1__c, Product_Category2__c, Product_Category3__c' +
		//	' from Agency_Report__c ' +
		//	' where needBatch__c = true';
		//rtId = [select Id,DeveloperName from RecordType where IsActive = true and SobjectType = 'Agency_Opportunity__c' and DeveloperName = 'Target'].Id;
		String query = 'select Agency_ID__c ' +
		    'from Agency_Opportunity__c ' +
		    'where RecordTypeId = \''+rtId+'\' and OCM_Term__c = \''+term+'\' group by Agency_ID__c';
		return new AggregateResultIterable(query);
	}

   	global void execute(Database.BatchableContext BC, List<AggregateResult> scope) {
   		Integer m = Date.today().month();
   		Integer y = Date.today().year();
   		y = m > 3 ? y : y - 1;
		//Id rtId = [select Id,DeveloperName from RecordType where IsActive = true and SobjectType = 'Agency_Opportunity__c' and DeveloperName = 'Target'].Id;
		//Set<String> pcIdSet = new Set<String>();
		//for (SObject so : scope) {
		//	Agency_Report__c aopp = (Agency_Report__c) so;
		//	pcIdSet.add(aopp.Product_Category1__c);
		//	pcIdSet.add(aopp.Product_Category2__c);
		//	pcIdSet.add(aopp.Product_Category3__c);
		//	aopp.BatchUpdateDatetime__c = Datetime.now();
		//}
		//if (scope.size() > 0) {
		//	update scope;
		//}
		//system.debug(pcIdSet);
		Set<String> agencyIdSet = new Set<String>();
		for (AggregateResult so : scope) {
			String agencyId = (String)so.get('Agency_ID__c');
			agencyIdSet.add(agencyId);
		}

		List<Agency_Opportunity__c> targetList = [select Id, Agency_Hospital_Target__c, Department_Cateogy__c, Product_Category__r.Name2__c, Product_Category__r.OPD_Flg__c, Product_Category__r.SIS_Flg__c from Agency_Opportunity__c 
												where RecordTypeId = :rtId and Agency_ID__c in :agencyIdSet and Is_OPDSIS_Target__c = true];

		//group by 产品1的count数
		AggregateResult[] product1Counts = [select Agency_Hospital__c, Department_Cateogy__c, Purpose_Type__c, Product_Category1__r.Name2__c pname, count(Id) cnt, max(Report_Date__c) rpDate 
			from Agency_Report__c 
			where Product_Category1__c != null and FISCAL_YEAR(Report_Date__c) = :y and Agency_ID__c in :agencyIdSet
			group by Agency_Hospital__c, Department_Cateogy__c, Purpose_Type__c, Product_Category1__r.Name2__c order by max(Report_Date__c)];
		//OPD/SIS用
		Map<String, Integer> count1 = new Map<String, Integer>();
		//非OPD/SIS用
		Map<String, Integer> count1_Target = new Map<String, Integer>();
		Map<String, Date> maxDate1 = new Map<String, Date>();
		Map<String, Date> maxDate1_Target = new Map<String, Date>();
		
		for (AggregateResult product1Count : product1Counts) {
			String ahl = (String)product1Count.get('Agency_Hospital__c');
			String pt = (String)((String)product1Count.get('Purpose_Type__c')).right(3);
			String pname = (String)product1Count.get('pname');
			String dc = (String)product1Count.get('Department_Cateogy__c');
			Integer cnt = (Integer)product1Count.get('cnt');
			Date rpDate = (Date)product1Count.get('rpDate');

			//key = 医院＋战略科室＋OPD/SIS+产品名
			String key = ahl+':'+dc+':'+pt+':'+pname;
			if (pt != 'OPD' && pt != 'SIS') {
				//key = 医院＋战略科室＋产品名
				key = ahl+':'+dc+':'+pname;
				if(count1_Target.containsKey(key)) {
					cnt = count1_Target.get(key) + cnt;
				}
				count1_Target.put(key, cnt);
				maxDate1_Target.put(key, rpDate);
			} else {
				if(count1.containsKey(key)) {
					cnt = count1.get(key) + cnt;
				}
				count1.put(key, cnt);
				maxDate1.put(key, rpDate);
			}
			
		}

		AggregateResult[] product2Counts = [select Agency_Hospital__c, Department_Cateogy__c, Purpose_Type__c, Product_Category2__r.Name2__c pname, count(Id) cnt, max(Report_Date__c) rpDate 
			from Agency_Report__c 
			where Product_Category2__c != null and FISCAL_YEAR(Report_Date__c) = :y and Agency_ID__c in :agencyIdSet
			group by Agency_Hospital__c, Department_Cateogy__c, Purpose_Type__c, Product_Category2__r.Name2__c order by max(Report_Date__c)];
		Map<String, Integer> count2 = new Map<String, Integer>();
		Map<String, Integer> count2_Target = new Map<String, Integer>();
		Map<String, Date> maxDate2 = new Map<String, Date>();
		Map<String, Date> maxDate2_Target = new Map<String, Date>();

		for (AggregateResult product2Count : product2Counts) {
			String ahl = (String)product2Count.get('Agency_Hospital__c');
			String pt = (String)((String)product2Count.get('Purpose_Type__c')).right(3);
			String pname = (String)product2Count.get('pname');
			String dc = (String)product2Count.get('Department_Cateogy__c');
			Integer cnt = (Integer)product2Count.get('cnt');
			Date rpDate = (Date)product2Count.get('rpDate');

			String key = ahl+':'+dc+':'+pt+':'+pname;
			if (pt != 'OPD' && pt != 'SIS') {
				//key = 医院＋战略科室＋产品名
				key = ahl+':'+dc+':'+pname;
				if(count2_Target.containsKey(key)) {
					cnt = count2_Target.get(key) + cnt;
				}
				count2_Target.put(key, cnt);
				maxDate2_Target.put(key, rpDate);
			} else {
				if(count2.containsKey(key)) {
					cnt = count2.get(key) + cnt;
				}
				count2.put(key, cnt);
				maxDate2.put(key, rpDate);
			}
		}

		AggregateResult[] product3Counts = [select Agency_Hospital__c, Department_Cateogy__c, Purpose_Type__c, Product_Category3__r.Name2__c pname, count(Id) cnt, max(Report_Date__c) rpDate 
			from Agency_Report__c 
			where Product_Category3__c != null and FISCAL_YEAR(Report_Date__c) = :y and Agency_ID__c in :agencyIdSet
			group by Agency_Hospital__c, Department_Cateogy__c, Purpose_Type__c, Product_Category3__r.Name2__c order by max(Report_Date__c)];
		Map<String, Integer> count3 = new Map<String, Integer>();
		Map<String, Integer> count3_Target = new Map<String, Integer>();
		Map<String, Date> maxDate3 = new Map<String, Date>();
		Map<String, Date> maxDate3_Target = new Map<String, Date>();

		for (AggregateResult product3Count : product3Counts) {
			String ahl = (String)product3Count.get('Agency_Hospital__c');
			String pt = (String)((String)product3Count.get('Purpose_Type__c')).right(3);
			String pname = (String)product3Count.get('pname');
			String dc = (String)product3Count.get('Department_Cateogy__c');
			Integer cnt = (Integer)product3Count.get('cnt');
			Date rpDate = (Date)product3Count.get('rpDate');

			String key = ahl+':'+dc+':'+pt+':'+pname;
			if (pt != 'OPD' && pt != 'SIS') {
				//key = 医院＋战略科室＋产品名
				key = ahl+':'+dc+':'+pname;
				if(count3_Target.containsKey(key)) {
					cnt = count3_Target.get(key) + cnt;
				}
				count3_Target.put(key, cnt);
				maxDate3_Target.put(key, rpDate);
			} else {
				if(count3.containsKey(key)) {
					cnt = count3.get(key) + cnt;
				}
				count3.put(key, cnt);
				maxDate3.put(key, rpDate);
			}
		}

		for (Agency_Opportunity__c target : targetList) {
			String pt = target.Product_Category__r.OPD_Flg__c ? 'OPD' : target.Product_Category__r.SIS_Flg__c ? 'SIS' : '';
			String key = target.Agency_Hospital_Target__c+':'+target.Department_Cateogy__c+':'+pt+':'+target.Product_Category__r.Name2__c;
			//system.debug(key);
			Integer count = 0;
			Date mDate = null;
			if (count1.containsKey(key)) {
				count += count1.get(key);
				Date m1Date = maxDate1.get(key);
				if (mDate == null || m1Date > mDate) {
					mDate = m1Date;
				}
			}
			if (count2.containsKey(key)) {
				count += count2.get(key);
				Date m2Date = maxDate2.get(key);
				if (mDate == null || m2Date > mDate) {
					mDate = m2Date;
				}
			}
			if (count3.containsKey(key)) {
				count += count3.get(key);
				Date m3Date = maxDate3.get(key);
				if (mDate == null || m3Date > mDate) {
					mDate = m3Date;
				}
			}
			target.Product_Category_Rpt_Count__c = count;
			if (mDate != null) target.MaxActivityDate__c = mDate;
			if (count == 0) target.Product_Category_Rpt_Count__c = null;
		}

		List<Agency_Opportunity__c> targetList2 = [select Id, Agency_Hospital_Target__c, Department_Cateogy__c, Product_Category__r.Name2__c, Product_Category__r.OPD_Flg__c, Product_Category__r.SIS_Flg__c from Agency_Opportunity__c 
												where RecordTypeId = :rtId and Agency_ID__c in :agencyIdSet and Is_OPDSIS_Target__c != true];

		for (Agency_Opportunity__c target : targetList2) {
			String key = target.Agency_Hospital_Target__c+':'+target.Department_Cateogy__c+':'+target.Product_Category__r.Name2__c;
			Integer count = 0;
			Date mDate = null;
			if (count1_Target.containsKey(key)) {
				count += count1_Target.get(key);
				Date m1Date = maxDate1_Target.get(key);
				if (mDate == null || m1Date > mDate) {
					mDate = m1Date;
				}
			}
			if (count2_Target.containsKey(key)) {
				count += count2_Target.get(key);
				Date m2Date = maxDate2_Target.get(key);
				if (mDate == null || m2Date > mDate) {
					mDate = m2Date;
				}
			}
			if (count3_Target.containsKey(key)) {
				count += count3_Target.get(key);
				Date m3Date = maxDate3_Target.get(key);
				if (mDate == null || m3Date > mDate) {
					mDate = m3Date;
				}
			}
			if (mDate != null) target.MaxActivityDate__c = mDate;
			target.Product_Category_Rpt_Count__c = count;
			if (count == 0) target.Product_Category_Rpt_Count__c = null;
		}

		if (targetList.size() > 0) {
			update targetList;
		}
		if (targetList2.size() > 0) {
			update targetList2;
		}
		
		//List<Agency_Opportunity__c> targetList = new List<Agency_Opportunity__c>();
		//List<Agency_Opportunity__c> targetList2 = new List<Agency_Opportunity__c>();
		//for (Agency_Opportunity__c so : scope) {
		//	if (so.Department_Cateogy__c == null) {
		//		targetList.add(so);
		//	} else {
		//		targetList2.add(so);
		//	}
		//}

		//List<Agency_Opportunity__c> targetList = [select Id, Agency_Hospital_Target__c, Department_Cateogy__c, Product_Category__r.Name2__c, Product_Category__r.OPD_Flg__c, Product_Category__r.SIS_Flg__c from Agency_Opportunity__c 
		//											where RecordTypeId = :rtId /*and Product_Category__c in :pcIdSet*/ and Department_Cateogy__c = null];

		//system.debug(targetList);
		


		//List<Agency_Opportunity__c> targetList2 = [select Id, Agency_Hospital_Target__c, Department_Cateogy__c, Product_Category__r.Name2__c, Product_Category__r.OPD_Flg__c, Product_Category__r.SIS_Flg__c from Agency_Opportunity__c 
		//											where RecordTypeId = :rtId and Product_Category__c in :pcIdSet and Department_Cateogy__c != null];

	}
	
	global void finish(Database.BatchableContext BC) {
		
	}
	
}