package pwc.taxtech.atms.common;

import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import org.apache.commons.io.IOUtils;
import org.nutz.lang.Lang;
import org.springframework.core.io.ClassPathResource;

import pwc.taxtech.atms.dpo.EnterpriseAccountSetOrgDto;

public class CommonUtils {
    public static final int BATCH_NUM = 500;
    
    public static String getUUID() {
        return UUID.randomUUID().toString().toUpperCase();
    }
    
    public static <T> T copyProperties(Object sourceObject, T targetObject) {
        Lang.copyProperties(sourceObject, targetObject);
        return targetObject;
    }
    
    /**
     * Determines whether [is date time overlapp] [the specified start].
     * @param organiztionAccountSetList
     * @return
     */
    public static boolean isOrganizationDateTimeOverlap(List<EnterpriseAccountSetOrgDto> organiztionAccountSetList) {
        
        if (organiztionAccountSetList == null || organiztionAccountSetList.isEmpty()) {
            return false;
        }
        
        for (int i = organiztionAccountSetList.size() - 1; i >= 0; i--)
        {
            organiztionAccountSetList.get(i).setOverlapList(new ArrayList<EnterpriseAccountSetOrgDto>());
            for (int j = i - 1; j >= 0; j--)
            {
                if (isDateTimeOverlap(organiztionAccountSetList.get(i).getEffectiveDate(),
                        organiztionAccountSetList.get(i).getExpiredDate(),
                        organiztionAccountSetList.get(j).getEffectiveDate(),
                        organiztionAccountSetList.get(j).getExpiredDate()
                    ))
                {
                    organiztionAccountSetList.get(i).getOverlapList().add(organiztionAccountSetList.get(j));
                }
            }
        }
        if (organiztionAccountSetList.stream().anyMatch(sa -> !sa.getOverlapList().isEmpty())) {
            return true;
        }
        return false;
    }
    
    public static boolean validateOnlyOncePerYear(List<EnterpriseAccountSetOrgDto> organiztionAccountSetList) {
        
        List<String> accountSetIdList = organiztionAccountSetList.stream()
                .map(sa -> sa.getEnterpriseAccountSetId()).distinct().collect(Collectors.toList());
        
        for(String accountSetId: accountSetIdList) {
            List<EnterpriseAccountSetOrgDto> sameAccountSetList = organiztionAccountSetList.stream()
                    .filter(sa -> sa.getEnterpriseAccountSetId().equals(accountSetId)).collect(Collectors.toList());
            for(int i = 0; i < sameAccountSetList.size() -1; i++) {
                for(int j = i+1; j<sameAccountSetList.size(); j++) {
                    EnterpriseAccountSetOrgDto first = sameAccountSetList.get(i);
                    EnterpriseAccountSetOrgDto second = sameAccountSetList.get(j);
                    
                    //DateTime firstE = new DateTime
                    if(first.getExpiredDate()!=null && second.getEffectiveDate()!=null) {
                        Calendar firstExpired = Calendar.getInstance();
                        firstExpired.setTime(first.getExpiredDate());
                        Calendar secondEffective = Calendar.getInstance();
                        secondEffective.setTime(second.getEffectiveDate());
                        if(firstExpired.get(Calendar.YEAR) == secondEffective.get(Calendar.YEAR)) {
                            return false;
                        }
                    }
                    if(first.getEffectiveDate()!=null && second.getExpiredDate()!=null) {
                        Calendar firstEffective = Calendar.getInstance();
                        firstEffective.setTime(first.getEffectiveDate());
                        Calendar secondExpired = Calendar.getInstance();
                        secondExpired.setTime(second.getExpiredDate());
                        if(firstEffective.get(Calendar.YEAR) == secondExpired.get(Calendar.YEAR)) {
                            return false;
                        }
                    }
                }
            }
        }
        return true;
    }
    
    /**
     * Determines whether [is date time overlapp] [the specified start].
     * @param start - The start
     * @param end - The end
     * @param compareStart - The compare start
     * @param compareEnd - The compare end
     * @return true - there is overlap; false - there is no overlap
     */
    public static boolean isDateTimeOverlap(Date start, Date end, Date compareStart, Date compareEnd) {
        
        //1/1/0001 12:00:00 AM  (Equals Date.MinValue)
        //9999/12/31 23:59:59 PM (Equals Date.MaxValue)
        
        Calendar calMin = Calendar.getInstance();
        calMin.set(0001, 1, 1, 0, 0, 0);
        Calendar calMax = Calendar.getInstance();
        calMax.set(9999, 12, 32, 23, 59, 59);

        start = start == null ? calMin.getTime() : start;
        end = end == null ? calMin.getTime() : end;
        compareStart = compareStart == null ? calMin.getTime() : compareStart;
        compareEnd = compareEnd == null ? calMin.getTime() : compareEnd;
        
        if(start.compareTo(compareEnd)<=0 && end.compareTo(compareStart)>=0) {
            return true;
        }
        
        return false;
    }
    
    
    public static String readClasspathFileToString(String path) {
        String text = null;;
        try {
            ClassPathResource classPathResource = new ClassPathResource(path);
            text = IOUtils.toString(classPathResource.getInputStream(), "UTF-8");
        } catch (IOException e) {
          throw Lang.wrapThrow(e);
        }
        return text;
    }

    public static <T> List<List<T>> subListWithLen(List<T> source, int len) {
        if (source == null || source.size() == 0 || len < 1) {
            return Collections.emptyList();
        }
        List<List<T>> result = new ArrayList<>();
        int count = (source.size() + len - 1) / len;
        for (int i = 0; i < count; i++) {
            List<T> value;
            if ((i + 1) * len < source.size()) {
                value = source.subList(i * len, (i + 1) * len);
            } else {
                value = source.subList(i * len, source.size());
            }
            result.add(value);
        }
        return result;
    }


}