package com.huiju.estateagents.task;

import lombok.Data;
import lombok.experimental.Accessors;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class LunarUtils {
    private final static String api = "https://www.hko.gov.hk/tc/gts/time/calendar/text/files/T%sc.txt";

    private Integer[] solarDate;
    private Lunar lunarDate;

    private List<Lunar> lunarList = new ArrayList<>();

    /**
     *
     * @param solarDate 公历 yyyy-mm-dd 格式
     */
    public LunarUtils(String solarDate) throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        String[] dateInfo = solarDate.split("-");
        this.solarDate = new Integer[]{Integer.parseInt(dateInfo[0]), Integer.parseInt(dateInfo[1]), Integer.parseInt(dateInfo[2])};

        getLunarData(dateInfo[0]);
        this.lunarDate = getLunarDate();
    }

    /**
     * 是否对应的阴历
     * @param lunarData 格式 08-15 代表 八月十五
     * @return
     */
    public boolean is(String lunarData) {
        String[] dt = lunarData.split("-");
        int mon = Integer.parseInt(dt[0]);
        int day = Integer.parseInt(dt[1]);

        if (lunarDate == null) {
            return false;
        }

        return lunarDate.getLunar()[0].equals(mon) && lunarDate.getLunar()[1].equals(day);
    }

    private Lunar getLunarDate() {
        for (Lunar item: lunarList) {
            if (solarDate[0].equals(item.getSolar()[0]) &&
                    solarDate[1].equals(item.getSolar()[1]) &&
                    solarDate[2].equals(item.getSolar()[2])) {
                return item;
            }
        }
        return null;
    }

    /**
     * 从网络上获取文件
     * @param yearStr
     * @return
     * @throws NoSuchAlgorithmException
     * @throws KeyStoreException
     * @throws KeyManagementException
     * @throws UnsupportedEncodingException
     */
    private InputStream getLunarStreamFromNet(String yearStr) throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException, UnsupportedEncodingException {
        String url = String.format(api, yearStr);

        RestTemplate restTemplate = getRestTemplate();
        // 下载内容为繁体中文
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(Charset.forName("BIG5")));
        byte[] bytes = restTemplate.getForObject(url, byte[].class);
        return new ByteArrayInputStream(bytes);
    }

    /**
     * 本地读取文件。 此处有个问题. txt 原来是 BIG5 编码。打包之后变成 UTF8 了，但是文件内容没有正确转码
     * @param yearStr
     * @return
     * @throws IOException
     */
    private InputStream getLunarStreamFromLocal(String yearStr) throws IOException {
        String fname = String.format("lunar/T%sc.txt", yearStr);
//        return Thread.currentThread().getContextClassLoader().getResourceAsStream(fname);
        return null;
    }

    private void getLunarData(String yearStr) throws IOException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException {
        // 如果本地不存在, 则从网络上读取
        InputStream inputStream = getLunarStreamFromLocal(yearStr);
        if (null == inputStream) {
            inputStream = getLunarStreamFromNet(yearStr);
        }
        BufferedReader br = new BufferedReader(new InputStreamReader(inputStream, "BIG5"));
        String line;
        Lunar last = null;
        // 记录里面开始日期没有月份, 所以需要记录最开始有月的农历
        Lunar firstMonthLunar = null;
        while ( (line = br.readLine()) != null ) {
            if(!line.trim().equals("")){
                Lunar lunar = new Lunar(line, last);
                if (lunar.getSolar() == null) {
                    continue;
                }
                lunarList.add(lunar);
                last = lunar;
                if (last.getLunar()[0] != null && firstMonthLunar == null) {
                    firstMonthLunar = last;
                }
            }
        }

        // 修正开始没有月份的日期
        if (null != firstMonthLunar) {
            Integer month = firstMonthLunar.getLunar()[0];
            int firstMonth = month == 1 ? 12 : month - 1;

            for (Lunar lunar: lunarList) {
                if (null == lunar.getLunar()[0]) {
                    lunar.setLunar(new Integer[]{firstMonth, lunar.getLunar()[1]});
                } else {
                    break;
                }
            }
        }
    }

    @Data
    @Accessors(chain = true)
    public static class Lunar {
        Integer[] solar;
        Integer[] lunar;
        String weekDay;

        final List<String> lunarDays = new ArrayList<String>() {{
            add("初一"); add("初二"); add("初三"); add("初四"); add("初五");
            add("初六"); add("初七"); add("初八"); add("初九"); add("初十");
            add("十一"); add("十二"); add("十三"); add("十四"); add("十五");
            add("十六"); add("十七"); add("十八"); add("十九"); add("二十");
            add("廿一"); add("廿二"); add("廿三"); add("廿四"); add("廿五");
            add("廿六"); add("廿七"); add("廿八"); add("廿九"); add("三十");
        }};

        final List<String> lunarMonths = new ArrayList<String>() {{
            add("正月"); add("二月"); add("三月"); add("四月"); add("五月"); add("六月");
            add("七月"); add("八月"); add("九月"); add("十月"); add("十一月"); add("十二月");
        }};

        Lunar(String str, Lunar last) {
            String pattern = "(\\S+)\\s+(\\S+)\\s+(\\S+)";
            Pattern r = Pattern.compile(pattern);
            Matcher m = r.matcher(str);

            if (m.find()) {
                String f = m.group(1);
                if (null != f && !"".equals(f)) {
                    String[] dt = f.replace("年", " ")
                            .replace("月", " ")
                            .replace("日", "")
                            .split(" ");
                    if (dt.length == 3) {
                        solar = new Integer[]{Integer.parseInt(dt[0]), Integer.parseInt(dt[1]), Integer.parseInt(dt[2])};
                    }
                }

                String lunarTmp = m.group(2);
                if (null != lunarTmp && !"".equals(lunarTmp) && null != solar) {
                    int monInx = lunarMonths.indexOf(lunarTmp);
                    if (monInx > -1) {
                        // 如果是 lunarTmp 是二月, 意思今天是 二月初一 也就是 02-01
                        // monInx = 1 , 所以需要  monInx + 1, day 置为 1
                        lunar = new Integer[]{monInx + 1, 1};
                    } else {
                        int inx = lunarDays.indexOf(lunarTmp);
                        Integer mon = null != last ? last.getLunar()[0] : null;
                        //
                        lunar = new Integer[]{mon, inx + 1};
                    }
                }

                weekDay = m.group(3);
            }
        }
    }

    private RestTemplate getRestTemplate()
            throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        TrustStrategy acceptingTrustStrategy = (X509Certificate[] chain, String authType) -> true;

        SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom()
                .loadTrustMaterial(null, acceptingTrustStrategy)
                .build();

        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext);
        CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();

        requestFactory.setHttpClient(httpClient);
        return new RestTemplate(requestFactory);
    }


//    public static void main(String[] args) {
//        LunarUtils lunarUtils;
//        try {
//            lunarUtils = new LunarUtils("2020-12-23");
//            System.out.println(lunarUtils.is("11-09"));
//        } catch (IOException | NoSuchAlgorithmException | KeyStoreException | KeyManagementException e) {
//            e.printStackTrace();
//        }
//    }
}
