package com.infinite.focus.server.payment;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;

import com.infinite.focus.server.auth.AccessCodeRepository;
import com.infinite.focus.server.auth.AccountRepository;
import com.infinite.focus.server.auth.AdminRepository;
import com.infinite.focus.server.auth.AvatarRepository;
import com.infinite.focus.server.auth.ConfirmationTokenRepository;
import com.infinite.focus.server.auth.DistrictRepository;
import com.infinite.focus.server.auth.EmailSenderService;
import com.infinite.focus.server.auth.InstructorRepository;
import com.infinite.focus.server.auth.Message;
import com.infinite.focus.server.auth.PayKickStartService;
import com.infinite.focus.server.auth.SchoolRepository;
import com.infinite.focus.server.auth.StudentRepository;

@CrossOrigin(origins = "http://localhost:8383")
@RestController
@RequestMapping("api/payment")

public class PayKickStartController {
	
		private AccountRepository accountRepository;
		private StudentRepository studentRepository;
		private InstructorRepository instructorRepository;
		private AvatarRepository avatarRepository;
	    private BCryptPasswordEncoder bCryptPasswordEncoder;
	    private AdminRepository adminRepository;
	    private SchoolRepository schoolRepository;
	    private DistrictRepository districtRepository;
	    private AccessCodeRepository accessCodeRepository;
	    
	    @Autowired
		private ConfirmationTokenRepository confirmationTokenRepository;
		
		@Autowired
		private EmailSenderService emailSenderService;
		
		@Autowired
		private PayKickStartService payKickStartService;
		
		@Autowired
		private InstantPaymentNotificationRepository instantPaymentNotificationRepository;
		
	    public PayKickStartController(DistrictRepository districtRepository, SchoolRepository schoolRepository, AdminRepository adminRepository, AvatarRepository avatarRepository,
	    		InstructorRepository instructorRepository, StudentRepository studentRepository,AccountRepository accountRepository, BCryptPasswordEncoder bCryptPasswordEncoder, AccessCodeRepository accessCodeRepository) {
	    	
	    	this.districtRepository = districtRepository;
	    	this.schoolRepository = schoolRepository;
	    	this.adminRepository = adminRepository;
	    	this.avatarRepository = avatarRepository;
	    	this.bCryptPasswordEncoder= bCryptPasswordEncoder;
	    	this.instructorRepository = instructorRepository;
	    	this.studentRepository = studentRepository;
	    	this.accountRepository = accountRepository;
	    	this.accessCodeRepository = accessCodeRepository;
			
		}
	    
	    @PostMapping(value = "/paykickstart-notifications")
	    @ResponseBody
	    public ResponseEntity<InstantPaymentNotification> paykickstartNotificationTest(
	    		@RequestParam HashMap<String, String> queryMap
	    ) throws InvalidKeyException, SignatureException, NoSuchAlgorithmException, IOException{
	    	
	    	Set setQuery = queryMap.entrySet();
	        
	        Iterator iteratorQuery = setQuery.iterator();
	        
	        while(iteratorQuery.hasNext()) {
	             Map.Entry entry = (Map.Entry) iteratorQuery.next();
	    //         System.out.println(entry.getKey() +" => " + entry.getValue());
	        }
	        
	        
	    	final String secret_key = "vSyq6faTF9iV";
	    	
	    	List<String> licenses = new ArrayList<String>();
	    	
	    	String hash = "";
	    	String verification_code ="";
	    	
	    	
	    	if(queryMap.containsKey("hash")) {
	    		hash = queryMap.get("hash");
	    		queryMap.remove("hash");
	    	}else {
   			    throw new ResponseStatusException(HttpStatus.NOT_FOUND, "The hash not found!!!");
	    	}
	    	
	    	if(queryMap.containsKey("verification_code")) {
	    		verification_code = queryMap.get("verification_code");
	    		queryMap.remove("verification_code");
	    	}else {
   			    throw new ResponseStatusException(HttpStatus.NOT_FOUND, "The verification_code not found!!!");
	    	}
	    	
	    	if(queryMap.containsKey("licenses")) {
  				licenses = Arrays.asList(queryMap.get("licenses").split(","));
  				if(licenses.isEmpty()){
  	   			    throw new ResponseStatusException(HttpStatus.NOT_FOUND, "The licenses not found!!!");
  				}
  			} else {
   			    throw new ResponseStatusException(HttpStatus.NOT_FOUND, "The licenses not found!!!");
  			}
	    	
	    	Map<String, String> dataMap = new TreeMap<String, String>(queryMap);
	    	
	    	String data ="";
	    	
	        Set set = dataMap.entrySet();
	        
	        Iterator iterator = set.iterator();
	        
	        while(iterator.hasNext()) {
	             Map.Entry entry = (Map.Entry) iterator.next();
	             String value = dataMap.get(entry.getKey());
	       //      System.out.println(value);
	             if(value!=null) {
	            	 value = value.trim();
	            	 if(!value.equals("null")) {
	            		 if(!value.isEmpty()) {
	            			 if(!value.equals("0")) {
	            				 data+=value.trim();
		            			 if(iterator.hasNext()) {
		            				 data+="|";
		            			 }
	            			 }
	            		 }
	            	 }
	             }
	        }
	    	
	    //	System.out.println(data);
	    	String hmac = HmacSha1Signature.calculateRFC2104HMAC(data, secret_key);
	    	
	    	if(!hash.equals(hmac)){
   			    throw new ResponseStatusException(HttpStatus.CONFLICT, "The hash not matched!!!");
	    	}
	    	
    		InstantPaymentNotification instantPaymentNotification = new InstantPaymentNotification();
	    	
    		instantPaymentNotification.setAffiliate_commission_amount(queryMap.get("affiliate_commission_amount"));
    		instantPaymentNotification.setAffiliate_commission_percent(queryMap.get("affiliate_commission_percent"));
    		instantPaymentNotification.setAffiliate_email(queryMap.get("affiliate_email"));
    		instantPaymentNotification.setAffiliate_first_name(queryMap.get("affiliate_first_name"));
    		instantPaymentNotification.setAffiliate_last_name(queryMap.get("affiliate_last_name"));
    		instantPaymentNotification.setAmount(queryMap.get("amount"));
    		instantPaymentNotification.setBilling_address_1(queryMap.get("billing_address_1"));
    		instantPaymentNotification.setBilling_address_2(queryMap.get("billing_address_2"));
    		instantPaymentNotification.setBilling_city(queryMap.get("billing_city"));
    		instantPaymentNotification.setBilling_country(queryMap.get("billing_country"));
    		instantPaymentNotification.setBilling_state(queryMap.get("billing_state"));
  			instantPaymentNotification.setBilling_zip(queryMap.get("billing_zip"));
  			instantPaymentNotification.setBuyer_email(queryMap.get("buyer_email"));
  			instantPaymentNotification.setBuyer_first_name(queryMap.get("buyer_first_name"));
  			instantPaymentNotification.setBuyer_ip(queryMap.get("buyer_ip"));
  			instantPaymentNotification.setBuyer_last_name(queryMap.get("buyer_last_name"));
  			instantPaymentNotification.setBuyer_tax_name(queryMap.get("buyer_tax_name"));
  			instantPaymentNotification.setBuyer_tax_number(queryMap.get("buyer_tax_number"));
  			instantPaymentNotification.setCampaign_id(queryMap.get("campaign_id"));
  			instantPaymentNotification.setCampaign_name(queryMap.get("campaign_name"));
  			instantPaymentNotification.setCoupon_code(queryMap.get("coupon_code"));
  			instantPaymentNotification.setCoupon_rate(queryMap.get("coupon_rate"));
  			instantPaymentNotification.setCoupon_type(queryMap.get("coupon_type"));
  			instantPaymentNotification.setCurrency(queryMap.get("currency"));
  			instantPaymentNotification.setEvent(queryMap.get("event"));
  			instantPaymentNotification.setInvoice_id(queryMap.get("invoice_id"));
  			instantPaymentNotification.setIs_rebill(queryMap.get("is_rebill"));
  			instantPaymentNotification.setMode(queryMap.get("mode"));
  			instantPaymentNotification.setNext_billing_date(queryMap.get("next_billing_date"));
  			instantPaymentNotification.setPayment_processor(queryMap.get("payment_processor"));
  			instantPaymentNotification.setProduct_id(queryMap.get("product_id"));
  			instantPaymentNotification.setProduct_name(queryMap.get("product_name"));
  			instantPaymentNotification.setQuantity(queryMap.get("quantity"));
  			instantPaymentNotification.setRef_affiliate_commission_amount(queryMap.get("ref_affiliate_commission_amount"));
  			instantPaymentNotification.setRef_affiliate_commission_percent(queryMap.get("ref_affiliate_commission_percent"));
  			instantPaymentNotification.setRef_affiliate_email(queryMap.get("ref_affiliate_email") );
  			instantPaymentNotification.setRef_affiliate_first_name(queryMap.get("ref_affiliate_first_name"));
  			instantPaymentNotification.setRef_affiliate_last_name(queryMap.get("ref_affiliate_last_name"));
  			instantPaymentNotification.setShipping_address_1(queryMap.get("shipping_address_1"));
  			instantPaymentNotification.setShipping_address_2(queryMap.get("shipping_address_2"));
  			instantPaymentNotification.setShipping_city(queryMap.get("shipping_city"));
  			instantPaymentNotification.setShipping_country(queryMap.get("shipping_country"));
  			instantPaymentNotification.setShipping_state(queryMap.get("shipping_state"));
  			instantPaymentNotification.setShipping_zip(queryMap.get("shipping_zip"));
  			instantPaymentNotification.setTax_amount(queryMap.get("tax_amount"));
  			instantPaymentNotification.setTax_percent(queryMap.get("tax_percent"));
  			instantPaymentNotification.setTax_transaction_id(queryMap.get("tax_transaction_id"));
  			instantPaymentNotification.setTracking_id(queryMap.get("tracking_id"));
  			instantPaymentNotification.setTransaction_id(queryMap.get("transaction_id"));
  			instantPaymentNotification.setTransaction_time(queryMap.get("transaction_time"));
  			instantPaymentNotification.setTransaction_type(queryMap.get("transaction_type"));
  			instantPaymentNotification.setVendor_email(queryMap.get("vendor_email"));
  			instantPaymentNotification.setVendor_first_name(queryMap.get("vendor_first_name"));
  			instantPaymentNotification.setVendor_last_name(queryMap.get("vendor_last_name"));
  			instantPaymentNotification.setLicenses(queryMap.get("licenses"));
  			instantPaymentNotification.setHash(hash);
  			instantPaymentNotification.setVerification_code(verification_code);
	    	
  			instantPaymentNotificationRepository.save(instantPaymentNotification);
  			
  			if(queryMap.containsKey("event")) {
  				String event = queryMap.get("event");
  				if(
  					event.equalsIgnoreCase("sales") || 
  					event.equalsIgnoreCase("subscription-payment") || 
  					event.equalsIgnoreCase("subscription-created") || 
  					event.equalsIgnoreCase("subscription-completed") || 
  					event.equalsIgnoreCase("subscription-trial-start")) {
						for (String license_key : licenses) { 
							LicensesEnableDisableResponse licensesEnableDisableResponse = payKickStartService.enableLicenses(license_key);
					//		System.out.println("Event: " + event + " license_key: " + license_key + " message: " + licensesEnableDisableResponse.getMessage());
							if(licensesEnableDisableResponse.getSuccess() == 0) {
								throw new ResponseStatusException(HttpStatus.NOT_FOUND,licensesEnableDisableResponse.getMessage());
							}
	    	    		}
						return new ResponseEntity<InstantPaymentNotification>(instantPaymentNotification,HttpStatus.OK);
				} else if(
					event.equalsIgnoreCase("refund") || 
					event.equalsIgnoreCase("subscription-cancelled") || 
					event.equalsIgnoreCase("subscription-trial-end") || 
					event.equalsIgnoreCase("subscription-payment-failed")) {
						for (String license_key : licenses) { 
							LicensesEnableDisableResponse licensesEnableDisableResponse = payKickStartService.disableLicenses(license_key);
				//			System.out.println("Event: " + event+ " license_key: " + license_key + " message: " + licensesEnableDisableResponse.getMessage());
							if(licensesEnableDisableResponse.getSuccess() == 0) {
								throw new ResponseStatusException(HttpStatus.NOT_FOUND,licensesEnableDisableResponse.getMessage());
							}
	    	    		}
					return new ResponseEntity<InstantPaymentNotification>(instantPaymentNotification,HttpStatus.OK);
				}else {
					throw new ResponseStatusException(HttpStatus.NOT_FOUND,"The event is unknown!!!");
				}
  			} else {
				throw new ResponseStatusException(HttpStatus.NOT_FOUND,"The event is unknown!!!");
			}
  			
	    }  

}