package com.iformall.utils;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.NumberFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Stormeye
 * @since 2018.08.09
 */

public final class Utility {
    private final static Logger logger = LoggerFactory.getLogger(Utility.class);


//    @Autowired
//    private ReloadableResourceBundleMessageSource messageSource;

    public static String generateUUID() {
        return UUID.randomUUID().toString();
    }

    public static String generate32UUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    public static boolean isEmpty(CharSequence str) {
        if (str == null || str.length() == 0)
            return true;
        else
            return false;
    }

    public static boolean isBlank(CharSequence str) {
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((Character.isWhitespace(str.charAt(i)) == false)) {
                return false;
            }
        }
        return true;
    }

    /**
     * format time to "yyyy-MM-dd"
     * @param time
     * @return
     */
    public static String formatTime(int time){
        long t = time * 1000l;
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
        String ret = formatter.format(new Date(t));
        return ret;
    }
    /**
     * format timestamp to "yyyy-MM-dd HH:mm:ss"
     * @param time
     * @return
     */
    public static String formatTimestamp(int time){
        long t = time * 1000l;
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String ret = formatter.format(new Date(t));
        return ret;
    }

    /**
     * getSimpleRegionModel the day end time by given the time point
     * e.g. given timePoint is "2015.5.13 13:45:32", the returned day end time is "2015.5.13 23:59:59"
     * @param timePoint
     * @return
     */
    public static int getDayEndTime(int timePoint){
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
        long theTime = ((long)timePoint)*1000;
        calendar.setTimeInMillis(theTime);
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);
        calendar.clear();
        calendar.set(year, month, day, 23, 59, 59);
        int ret = (int)(calendar.getTimeInMillis()/1000);
        return ret;
    }

    public static int getDayStartTime(int timePoint) {
        Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT+8"));
        long theTime = ((long)timePoint)*1000;
        calendar.setTimeInMillis(theTime);
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH);
        int day = calendar.get(Calendar.DAY_OF_MONTH);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int minute = calendar.get(Calendar.MINUTE);
        int second = calendar.get(Calendar.SECOND);
        calendar.clear();
        calendar.set(year, month, day, 0, 0, 0);
        int ret = (int)(calendar.getTimeInMillis()/1000);
        return ret;
    }

    public static int getLastHourEndTime(int timePoint) {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd-HH");
        String curHour = sf.format(System.currentTimeMillis());
        int ret = timePoint;
        try {
            ret = (int)((sf.parse(curHour).getTime())/1000);
        } catch(ParseException ex) {
            ex.printStackTrace();
        }
        return ret - 1;
    }

    /**
     * Encrypt plain text
     * @param plainText
     * @return encrypted string for cvn2
     */
    public static String encryptText(String plainText) {

        return plainText;
    }

    /**
     * Decrypt to plain text
     * @param decryptedText
     * @return encrypted string for cvn2
     */
    public static String decryptedText(String decryptedText) {

        return decryptedText;
    }

    /**
     * Mask the bankcard Number, e.g. 18911113927 to 189******3927
     * @param idCardNo
     * @return masked phone number
     */
    public static String maskIdCard(String idCardNo) {
        if(isEmpty(idCardNo) || idCardNo.length() < 18) {
            return idCardNo;
        }
        return idCardNo.substring(0,4) + "**" + idCardNo.substring(6, 12) + "***" + idCardNo.substring(15, 18);
    }

    /**
     * Mask the bankcard Number, e.g. 18911113927 to 189******3927
     * @param bankCardNo
     * @return masked phone number
     */
    public static String maskBankCard(String bankCardNo) {
        if(bankCardNo.length() <= 8) {
            return bankCardNo;
        }
        return bankCardNo.substring(0,4) + "******" + bankCardNo.substring(bankCardNo.length() - 4, bankCardNo.length());
    }

    /**
     * Mask the user name, e.g.
     * @param userName
     * @return masked phone number
     */
    public static String maskUserName(String userName) {
        switch (userName.length()) {
            case 0:
            case 1:
                return "*";
            default:
                return userName.replaceAll(".", "*").replaceFirst(".$",userName.substring(userName.length() - 1));
        }
    }

    public static String maskPhoneNum(String phoneNum) {
        if(phoneNum==null || phoneNum.length() < 4) {
            return phoneNum;
        }
        return phoneNum.substring(0,3) + "****" + phoneNum.substring(phoneNum.length() - 4, phoneNum.length());
    }

    /**
     * Convert current time into int type. used for create_time/update time
     * @param
     * @return timestamp
     */
    public static int getCurrentTimeStamp() {
        if(debugCurrentTimeStamp == 0) {
            return (int) (System.currentTimeMillis() / 1000);
        }else {
            return debugCurrentTimeStamp;
        }
    }

    public static int convertDate2TimeStamp(Date date) {
            return (int) (date.getTime() / 1000);
    }


    private static int debugCurrentTimeStamp = 0;

    /**
     * For test purpose, getCurrentTimeStamp will return the timestamp if non-zero.
     * @param
     * @return timestamp
     */
    public static void setDebugCurrentTimeStamp(int timeStamp) {
        debugCurrentTimeStamp = timeStamp;
    }


    public static String generateInvitationCode(Set<String> existingCode){
        int invitationCode = (int)((Math.random()*9+1)*100000);
        if(existingCode != null){
            while(existingCode.contains(String.valueOf(invitationCode))){
                invitationCode++;
                if(invitationCode>=999999){
                    invitationCode = (int)((Math.random()*9+1)*100000);
                }
            }
        }
        return String.valueOf(invitationCode);
    }

    public static String generateOrderId(String gid) {
        if (null == gid) {
            return "";
        }
        return "SDLC" + gid.replaceAll("-", "");
    }

    public static String getDataFormatString(int currentSec) {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sf.format(((long) currentSec) * 1000);
    }

    public static String getDataFormatString2(int currentSec) {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy年MM月dd日");
        return sf.format(((long) currentSec) * 1000);
    }

    public static String getDataFormatString3(Date date) {
        SimpleDateFormat sf = new SimpleDateFormat("yyyy年MM月dd日");
        return sf.format(date);
    }

    public static String convertDecimal2PercentRate(BigDecimal rate) {
        NumberFormat percent = NumberFormat.getPercentInstance();
        percent.setMaximumFractionDigits(1);
        return percent.format(rate.setScale(3, BigDecimal.ROUND_DOWN));
    }

    public static String convertLineFeedCharacter(String msg){
        if(msg == null || msg.isEmpty()){
            return "";
        }
        msg = msg.replace("\\\\n", "\\n");
        return msg;
    }

    public static int getSimpleDayEndTime(int timePoint){
        Calendar ca = new GregorianCalendar();
        ca.setTime(new Date(((long) timePoint) * 1000));
        ca.set(Calendar.HOUR_OF_DAY, 23);
        ca.set(Calendar.MINUTE, 59);
        ca.set(Calendar.SECOND, 59);
        long ret = ca.getTime().getTime()/1000;
        return (int) ret;
    }

    public static String urlEncodeUTF8(String s) {
        try {
            return URLEncoder.encode(s, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new UnsupportedOperationException(e);
        }
    }

    public static String urlDecodeUTF8(String s) {
        try {
            return URLDecoder.decode(s, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new UnsupportedOperationException(e);
        }
    }

    public static int dateStringToTimeStamp(String dateStr){
        int timeStamp = 0;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            Date date = sdf.parse(dateStr);
            timeStamp= (int) (date.getTime()/1000);
        } catch (ParseException e) {
            logger.error("dateStringToTimeStamp exception = {}", e);
        }
        return timeStamp;
    }
    public static int dateStringToTimeStamp(String dateStr,String format){
        int timeStamp = 0;
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        try {
            Date date = sdf.parse(dateStr);
            timeStamp= (int) (date.getTime()/1000);
        } catch (ParseException e) {
            logger.error("dateStringToTimeStamp exception = {}", e);
        }
        return timeStamp;
    }
    public static Object convert(Object object, Class<?> type) {
        if (object instanceof Number) {
            Number number = (Number) object;
            if (type.equals(byte.class) || type.equals(Byte.class)) {
                return number.byteValue();
            }
            if (type.equals(short.class) || type.equals(Short.class)) {
                return number.shortValue();
            }
            if (type.equals(int.class) || type.equals(Integer.class)) {
                return number.intValue();
            }
            if (type.equals(long.class) || type.equals(Long.class)) {
                return number.longValue();
            }
            if (type.equals(float.class) || type.equals(Float.class)) {
                return number.floatValue();
            }
            if (type.equals(double.class) || type.equals(Double.class)) {
                return number.doubleValue();
            }
        }
        return object;
    }

    public static int getFirstDayByDate(final Date date) {
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        instance.set(instance.get(Calendar.YEAR), instance.get(Calendar.MONTH), 1, 0, 0, 0);
        int ret = (int) (instance.getTimeInMillis()/1000);
        return ret;
    }

    public static boolean decimalEqualsScale2(BigDecimal one , BigDecimal two) {
        if (one == null || two == null) {
            return false;
        }

        final BigDecimal o1 = one.setScale(2 , BigDecimal.ROUND_DOWN);
        final BigDecimal o2 = two.setScale(2 , BigDecimal.ROUND_DOWN);
        return o1.compareTo(o2) == 0;
    }

    public static int decimalCompareScale2(BigDecimal one , BigDecimal two) {
        if (one == null || two == null) {
            return -1;
        }
        final BigDecimal o1 = one.setScale(2 , BigDecimal.ROUND_DOWN);
        final BigDecimal o2 = two.setScale(2 , BigDecimal.ROUND_DOWN);
        return o1.compareTo(o2);
    }

    public static BigDecimal    setScale2RoundDown(BigDecimal one) {
        if (one == null) {
            return null;
        }
        return one.setScale(2, BigDecimal.ROUND_DOWN);
    }

    public static boolean isNumeric(String str){
        Pattern pattern = Pattern.compile("[0-9]*");
        Matcher isNum = pattern.matcher(str);
        if( !isNum.matches() ){
            return false;
        }
        return true;
    }

    public static String dateFormat(Date date, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        return sdf.format(date);
    }

    public static int getCurrentWeekStartTime(int dayTime) {
        Calendar currentDate = Calendar.getInstance();
        currentDate.setTime(new Date(dayTime * 1000L));
        currentDate.setFirstDayOfWeek(Calendar.MONDAY);
        currentDate.set(Calendar.HOUR_OF_DAY, 0);
        currentDate.set(Calendar.MINUTE, 0);
        currentDate.set(Calendar.SECOND, 0);
        currentDate.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
        return (int)(currentDate.getTimeInMillis() / 1000L);
    }

    public static int getCurrentWeekEndTime(int dayTime) {
        Calendar currentDate = Calendar.getInstance();
        currentDate.setTime(new Date(dayTime * 1000L));
        currentDate.setFirstDayOfWeek(Calendar.MONDAY);
        currentDate.set(Calendar.HOUR_OF_DAY, 23);
        currentDate.set(Calendar.MINUTE, 59);
        currentDate.set(Calendar.SECOND, 59);
        currentDate.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
        return (int)(currentDate.getTimeInMillis() / 1000L);
    }

    public static int getCurrentMonthStartTime(int dayTime) {
        Calendar currentDate = Calendar.getInstance();
        currentDate.setTime(new Date(dayTime * 1000L));
        currentDate.set(Calendar.HOUR_OF_DAY, 0);
        currentDate.set(Calendar.MINUTE, 0);
        currentDate.set(Calendar.SECOND, 0);
        currentDate.set(Calendar.DAY_OF_MONTH, currentDate
                .getActualMinimum(Calendar.DAY_OF_MONTH));
        return (int)(currentDate.getTimeInMillis() / 1000L);
    }

    public static int getCurrentMonthEndTime(int dayTime) {
        Calendar currentDate = Calendar.getInstance();
        currentDate.setTime(new Date(dayTime * 1000L));
        currentDate.set(Calendar.HOUR_OF_DAY, 23);
        currentDate.set(Calendar.MINUTE, 59);
        currentDate.set(Calendar.SECOND, 59);
        currentDate.set(Calendar.DAY_OF_MONTH, currentDate
                .getActualMaximum(Calendar.DAY_OF_MONTH));
        return (int)(currentDate.getTimeInMillis() / 1000L);
    }

    /**
     * format time to "yyyy-MM-dd"
     * @param time
     * @return
     */
    public static String formatTimeYYMMDDHH(int time){
        long t = time * 1000l;
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHH");
        String ret = formatter.format(new Date(t));
        return ret;
    }

    public static String formatTimeMMDD(int time){
        long t = time * 1000l;
        SimpleDateFormat formatter = new SimpleDateFormat("MMdd");
        String ret = formatter.format(new Date(t));
        return ret;
    }

    public static String formatTimeMMDotDD(int time) {
        long t = time * 1000l;
        SimpleDateFormat formatter = new SimpleDateFormat("MM.dd");
        String ret = formatter.format(new Date(t));
        return ret;
    }

    public static String formatTimeYmdHm(int time) {
        long t = time * 1000l;
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMddHHmm");
        String ret = formatter.format(new Date(t));
        return ret;
    }

    public static int getDayByType(int time, int type) {
        long t = time * 1000L;
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(t));
        return calendar.get(type);
    }

    public static int addTime(int time , int type , int nums) {
        long t = time * 1000L;
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date(t));
        calendar.add(type, nums);
        return (int)(calendar.getTimeInMillis() / 1000L);
    }

    public static BigDecimal convertCoord2Decimal(Integer coordLat) {
        return new BigDecimal(coordLat).divide(new BigDecimal(100000), 5, BigDecimal.ROUND_HALF_DOWN);
    }

    public static BigDecimal convertScale(Double amount) {
        return amount != null ? new BigDecimal(amount).setScale(1,BigDecimal.ROUND_HALF_DOWN) : BigDecimal.ZERO;
    }

    public static String convertLevel(String level) {
        if (level != null && level.matches("\\d+(.\\d+)?")) {
            return new BigDecimal(level)
                    .multiply(new BigDecimal(2.0))
                    .setScale(1, BigDecimal.ROUND_HALF_UP).toString();
        }
        return level;
    }

    public static String getUTFString(String content) {
        try {
            return new String(content.getBytes("ISO-8859-1"), "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 金额 分转换元（精确到2位小数）
     * @param money （单位分）
     * @return
     */
    public static BigDecimal getAmount(Integer money) {
        return new BigDecimal(money).divide(new BigDecimal(100), 2, BigDecimal.ROUND_DOWN);
    }

    public static String getDataFormatStringYYYYMMDDHHmmss(int currentSec) {
        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
        return sf.format(((long) currentSec) * 1000);
    }

    public static String getDataFormatStringYYYYMMDDHHmmss(Date currentDate) {
        SimpleDateFormat sf = new SimpleDateFormat("yyyyMMddHHmmss");
        return sf.format(currentDate);
    }

    public static Date getDateFromString(String timeEnd) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        return sdf.parse(timeEnd);
    }

    public static String getOrderNo() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = sdf.format(new Date());
        return dateStr.substring(0,4)+dateStr.substring(5,7)+dateStr.substring(8,10)+dateStr.substring(11,13)+dateStr.substring(14,16)+dateStr.substring(17,19)+RandomUtils.getNum(5);
    }

    /**
     * 金额 分转换元（精确到1位小数）
     * @param money （单位角）
     * @return
     */
    public static String getAmountStr(Integer money) {
        return new BigDecimal(money).divide(new BigDecimal(100), 2, BigDecimal.ROUND_DOWN).toString();
    }

    /**
     * format time to "yyyyMMdd"
     * @param time
     * @return
     */
    public static String formatTimeYmd(int time){
        long t = time * 1000l;
        SimpleDateFormat formatter = new SimpleDateFormat("yyyyMMdd");
        String ret = formatter.format(new Date(t));
        return ret;
    }


    public static boolean isFileExist(String filePath) {
        File path=new File(filePath);
        if(path.exists()){
            return true;
        }
        return false;
    }

    /**
     * @param text
     *            目标字符串
     * @param length
     *            截取长度
     * @param encode
     *            采用的编码方式
     * @return
     * @throws UnsupportedEncodingException
     */

    public static String substring(String text, int length, String encode)
            throws UnsupportedEncodingException {
        if (text == null) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        int currentLength = 0;
        for (char c : text.toCharArray()) {
            currentLength += String.valueOf(c).getBytes(encode).length;
            if (currentLength <= length) {
                sb.append(c);
            } else {
                break;
            }
        }
        return sb.toString();
    }


}
