/*
	Schedule: UpdateAgencyProductTargetSchedule
	引合いの製品区分をAからBに変更したとき、A目標も対象にしないといけないため、Batch側で修正する目標は全部にしないといけないです。
	TODO 今後データ量増加により、変更差分のbatchにする仕組みを考える必要です。
 */
global class UpdateAgencyOppProductTargetBatch implements Database.Batchable<AggregateResult> {
	
	String term;
	Id rtId;
	
	global UpdateAgencyOppProductTargetBatch() {
		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) {
		//Id rtId = [select Id,DeveloperName from RecordType where IsActive = true and SobjectType = 'Agency_Opportunity__c' and DeveloperName = 'Target'].Id;
		//String query = 'select Id, Agency_Hospital__c, Department_Cateogy__c, Product_Category1__c, Product_Category2__c, Product_Category3__c' +
		//    '  from Agency_Opportunity__c' +
		//    ' where RecordTypeId = :rtId and tem_OCM_Term__c = :term and needBatch__c = true'; // TODO Wangwf and aoop.XXXXX < LastModifiedDate';
		String query = 'select Agency_ID__c ' +
		    'from Agency_Opportunity__c ' +
		    'where RecordTypeId = \''+rtId+'\' and OCM_Term__c = \''+term+'\' group by Agency_ID__c';
		//return Database.getQueryLocator(query);
		return new AggregateResultIterable(query);
	}

   	global void execute(Database.BatchableContext BC, List<AggregateResult> scope) {
   		//Id rtId = [select Id,DeveloperName from RecordType where IsActive = true and SobjectType = 'Agency_Opportunity__c' and DeveloperName = 'Target'].Id;
   		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 from Agency_Opportunity__c 
												where RecordTypeId = :rtId and OCM_Term__c = :term and Agency_ID__c in :agencyIdSet and Is_OPDSIS_Target__c != true];
			
		AggregateResult[] product1Counts = [select Agency_Hospital__c, Department_Cateogy__c, Product_Category1__r.Name2__c pname, count(Id) cnt 
			from Agency_Opportunity__c 
			where Product_Category1__c != null and tem_OCM_Term__c = :term and Agency_ID__c in :agencyIdSet
			group by Agency_Hospital__c, Department_Cateogy__c , Product_Category1__r.Name2__c];
		Map<String, Integer> count1 = new Map<String, Integer>();
		for (AggregateResult product1Count : product1Counts) {
			String ahl = (String)product1Count.get('Agency_Hospital__c');
			String dc = (String)product1Count.get('Department_Cateogy__c');
			String name2 = (String)product1Count.get('pname');
			//String name2 = (String)p1.get('Name2__c');
			//String name2 = (String)((Map<String,Object>)product1Count.get('Product_Category1__r').get('Name2__c'));
			Integer cnt = (Integer)product1Count.get('cnt');
			String key = ahl+':'+dc+':'+name2;

			count1.put(key, cnt);
		}

		AggregateResult[] product2Counts = [select Agency_Hospital__c, Department_Cateogy__c, Product_Category2__r.Name2__c pname, count(Id) cnt 
			from Agency_Opportunity__c 
			where Product_Category2__c != null and tem_OCM_Term__c = :term and Agency_ID__c in :agencyIdSet
			group by Agency_Hospital__c, Department_Cateogy__c , Product_Category2__r.Name2__c];
		Map<String, Integer> count2 = new Map<String, Integer>();
		for (AggregateResult product2Count : product2Counts) {
			String ahl = (String)product2Count.get('Agency_Hospital__c');
			String dc = (String)product2Count.get('Department_Cateogy__c');
			String name2 = (String)product2Count.get('pname');
			//Map<String,Object> p2 = (Map<String,Object>)product2Count.get('Product_Category2__r');
			//String name2 = (String)p2.get('Name2__c');
			//String name2 = (String)product2Count.get('Product_Category2__r').get('Name2__c');
			Integer cnt = (Integer)product2Count.get('cnt');
			String key = ahl+':'+dc+':'+name2;

			count2.put(key, cnt);
		}

		AggregateResult[] product3Counts = [select Agency_Hospital__c, Department_Cateogy__c, Product_Category3__r.Name2__c pname, count(Id) cnt 
			from Agency_Opportunity__c 
			where Product_Category3__c != null and tem_OCM_Term__c = :term and Agency_ID__c in :agencyIdSet
			group by Agency_Hospital__c, Department_Cateogy__c , Product_Category3__r.Name2__c];
		Map<String, Integer> count3 = new Map<String, Integer>();
		for (AggregateResult product3Count : product3Counts) {
			String ahl = (String)product3Count.get('Agency_Hospital__c');
			String dc = (String)product3Count.get('Department_Cateogy__c');
			String name2 = (String)product3Count.get('pname');
			//Map<String,Object> p3 = (Map<String,Object>)product3Count.get('Product_Category3__r');
			//String name2 = (String)p3.get('Name2__c');
			//String name2 = (String)product3Count.get('Product_Category3__r').get('Name2__c');
			Integer cnt = (Integer)product3Count.get('cnt');
			String key = ahl+':'+dc+':'+name2;

			count3.put(key, cnt);
		}

		for (Agency_Opportunity__c target : targetList) {
			String key = target.Agency_Hospital_Target__c+':'+target.Department_Cateogy__c+':'+target.Product_Category__r.Name2__c;
			Integer count = 0;
			if (count1.containsKey(key)) {
				count += count1.get(key);
			}
			if (count2.containsKey(key)) {
				count += count2.get(key);
			}
			if (count3.containsKey(key)) {
				count += count3.get(key);
			}
			target.Product_Category_Opp_Count__c = count;
			if (count == 0) target.Product_Category_Opp_Count__c = null;
		}

		if (targetList.size() > 0) {
			update targetList;
		}
   		
		//Set<String> pcIdSet = new Set<String>();
		//for (Agency_Opportunity__c aopp : scope) {
		//	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);

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


	}
	
	global void finish(Database.BatchableContext BC) {
		//do nothing
	}
	
}