package com.nokia.sms;

import de.siegmar.fastcsv.reader.CsvReader;
import de.siegmar.fastcsv.reader.CsvRow;
import de.siegmar.fastcsv.writer.CsvWriter;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@SpringBootTest
class SyncTest {
    public static final String TEST_DIR = "test/";
    @Autowired
    private JdbcTemplate jdbcTemplate;

    /**
     * 筛选无在黑记录号码
     */
    @Test
    void testFindNoBlack() {
        String p1 = TEST_DIR + "data.csv";
        String p2 = TEST_DIR + "blacklist.csv";
        String r1 = TEST_DIR + "result1.csv";
        String r2 = TEST_DIR + "result2.csv";
        String phoneFile = TEST_DIR + "phones.csv";
        Set<String> phones = ConcurrentHashMap.newKeySet();
        Map<String, AtomicLong> phoneCount = new HashMap<>();
        try (CsvReader csvReader = CsvReader.builder().build(Paths.get(p1), StandardCharsets.UTF_8);
             OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(Paths.get(phoneFile)),
                     StandardCharsets.UTF_8);
             CsvWriter csvWriter = CsvWriter.builder().build(osw);) {
            for (CsvRow row : csvReader) {
                if (row.getOriginalLineNumber() == 1) {
                    continue;
                }

                String phone = row.getField(0);
                phones.add(phone);
                phoneCount.putIfAbsent(phone, new AtomicLong(0L));
                phoneCount.get(phone).incrementAndGet();
            }
            for (String phone : phones) {
                csvWriter.writeRow(phone);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(phones.size());
        try (CsvReader csvReader = CsvReader.builder().build(Paths.get(p2), StandardCharsets.UTF_8);
             OutputStreamWriter osw1 = new OutputStreamWriter(Files.newOutputStream(Paths.get(r1)),
                     StandardCharsets.UTF_8);
             CsvWriter csvWriter1 = CsvWriter.builder().build(osw1);
             OutputStreamWriter osw2 = new OutputStreamWriter(Files.newOutputStream(Paths.get(r2)),
                     StandardCharsets.UTF_8);
             CsvWriter csvWriter2 = CsvWriter.builder().build(osw2);) {
            Map<String, List<String>> map = new HashMap<>();
            for (CsvRow csvRow : csvReader) {
                map.put(csvRow.getField(0), csvRow.getFields());
            }
            for (String phone : phones) {
                for (Map.Entry<String, List<String>> entry : map.entrySet()) {
                    String key = entry.getKey();
                    if (key.equals(phone)) {
                        phones.remove(phone);
                        csvWriter2.writeRow(entry.getValue());
                    }
                }
            }
            for (String phone : phones) {
                csvWriter1.writeRow(phone, phoneCount.get(phone).toString());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(phones.size());
    }

    /**
     * 筛选在黑数据
     */
    @Test
    void testBlack() {
        String p1 = TEST_DIR + "blacklist.csv";
        String result = TEST_DIR + "black.csv";
        try (CsvReader csvReader = CsvReader.builder().build(Paths.get(p1), StandardCharsets.UTF_8);
             OutputStreamWriter osw = new OutputStreamWriter(Files.newOutputStream(Paths.get(result)),
                     StandardCharsets.UTF_8);
             CsvWriter csvWriter = CsvWriter.builder().build(osw);) {
            for (CsvRow row : csvReader) {
                if ("2".equals(row.getField(5))) {
                    continue;
                }

                csvWriter.writeRow(row.getFields());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 黑名单数据比对
     */
    @Test
    void testDiff() {
        Map<String, Map<String, String>> m1 = new HashMap<>();
        Map<String, Map<String, String>> m2 = new HashMap<>();
        String record = TEST_DIR + "blacklist_file.csv";
        String p1 = TEST_DIR + "data.csv";
        String p2 = TEST_DIR + "blacklist.csv";
        String r1 = TEST_DIR + "result1.csv";
        String r2 = TEST_DIR + "result2.csv";
        String d1 = TEST_DIR + "diff1.csv";
        String d2 = TEST_DIR + "diff2.csv";
        String o1 = TEST_DIR + "output1.csv";
        String o2 = TEST_DIR + "output2.csv";
        try {
            try (CsvReader csvReader = CsvReader.builder().build(Paths.get(p1), StandardCharsets.UTF_8)) {
                for (CsvRow row : csvReader) {
                    if (row.getOriginalLineNumber() == 1) {
                        continue;
                    }

                    m1.put(row.getField(0), new HashMap<String, String>() {{
                        put("phone", row.getField(0));
                        put("reason", row.getField(1));
                        put("start_time", row.getField(2));
                        put("end_time", row.getField(3));
                        put("suggestion", row.getField(4));
                    }});
                }
            }
            try (CsvReader csvReader = CsvReader.builder().build(Paths.get(p2), StandardCharsets.UTF_8)) {
                for (CsvRow row : csvReader) {
                    if (row.getOriginalLineNumber() == 1) {
                        continue;
                    }

                    m2.put(row.getField(0), new HashMap<String, String>() {{
                        put("phone", row.getField(0));
                        put("reason", row.getField(1));
                        put("start_time", row.getField(2));
                        put("end_time", row.getField(3));
                        put("hit_desc", row.getField(4));
                        put("operation_type", row.getField(5));
                        put("suggestion", row.getField(6));
                    }});
                }
            }
            try (OutputStreamWriter osw1 = new OutputStreamWriter(Files.newOutputStream(Paths.get(r1)),
                    StandardCharsets.UTF_8);
                 CsvWriter csvWriter1 = CsvWriter.builder().build(osw1);
                 OutputStreamWriter osw2 = new OutputStreamWriter(Files.newOutputStream(Paths.get(d1)),
                         StandardCharsets.UTF_8);
                 CsvWriter csvWriter2 = CsvWriter.builder().build(osw2);
                 OutputStreamWriter osw3 = new OutputStreamWriter(Files.newOutputStream(Paths.get(o1)),
                         StandardCharsets.UTF_8);
                 CsvWriter csvWriter3 = CsvWriter.builder().build(osw3);
            ) {
                csvWriter1.writeRow("黑名单号码", "入黑名单原因", "解黑建议", "开始时间", "结束时间", "入黑名单原因", "解黑建议", "开始时间", "结束时间", "命中策略说明", "操作类型", "是否一致", "不一致原因");
                csvWriter3.writeRow("不一致情况", "黑名单号码", "入黑名单原因", "解黑建议", "开始时间", "结束时间", "入黑名单原因", "解黑建议", "开始时间", "结束时间");
                for (Map<String, String> v1 : m1.values()) {
                    String phone = v1.get("phone");
                    Map<String, String> v2 = m2.getOrDefault(phone, new HashMap<>());
                    String flag = "是";
                    String diff = "";
                    String situation = "没有同步记录但是在黑数据中存在";
                    if (!v1.get("reason").equals(v2.get("reason"))) {
                        diff = "入黑名单原因、";
                    }
                    if (!v1.get("start_time").equals(v2.get("start_time"))) {
                        diff = diff + "开始时间、";
                    }
                    if (!v1.get("end_time").equals(v2.get("end_time"))) {
                        diff = diff + "结束时间、";
                    }
                    if (!v1.get("suggestion").equals(v2.get("suggestion"))) {
                        diff = diff + "解黑建议、";
                    }
                    if (CollectionUtils.isEmpty(v2)) {
                        diff = "数据库中没有记录";
                        csvWriter3.writeRow(situation, phone, v2.get("reason"), v2.get("suggestion"), v2.get("start_time"), v2.get("end_time"), v1.get("reason"), v1.get("suggestion"), v1.get("start_time"), v1.get("end_time"));
                    }
                    if (StringUtils.hasText(diff)) {
                        flag = "否";
                        csvWriter2.writeRow("黑名单号码", "入黑名单原因", "解黑建议", "开始时间", "结束时间", "入黑名单原因", "解黑建议", "开始时间", "结束时间", "命中策略说明", "操作类型", "是否一致", "不一致原因");
                        csvWriter2.writeRow(phone, v2.get("reason"), v2.get("suggestion"), v2.get("start_time"), v2.get("end_time"), v1.get("reason"), v1.get("suggestion"), v1.get("start_time"), v1.get("end_time"), v2.get("hit_desc"), v2.get("operation_type"), flag, diff);
                        csvWriter2.writeRow("黑名单号码", "入黑名单原因", "解黑建议", "开始时间", "结束时间", "命中策略说明", "操作类型", "同步文件名");
                        try (CsvReader csvReader = CsvReader.builder().build(Paths.get(record), StandardCharsets.UTF_8)) {
                            for (CsvRow row : csvReader) {
                                if (row.getOriginalLineNumber() == 1 || !phone.equals(row.getField(0))) {
                                    continue;
                                }
                                csvWriter2.writeRow(
                                        row.getField(0),
                                        row.getField(1),
                                        row.getField(6),
                                        row.getField(2),
                                        row.getField(3),
                                        row.getField(4),
                                        row.getField(5),
                                        row.getField(7)
                                );
                            }
                        }
                        csvWriter2.writeRow();
                    }
                    csvWriter1.writeRow(phone, v1.get("reason"), v1.get("suggestion"), v1.get("start_time"), v1.get("end_time"), v2.get("reason"), v2.get("suggestion"), v2.get("start_time"), v2.get("end_time"), v2.get("hit_desc"), v2.get("operation_type"), flag, diff);
                }
            }
            try (OutputStreamWriter osw1 = new OutputStreamWriter(Files.newOutputStream(Paths.get(r2)),
                    StandardCharsets.UTF_8);
                 CsvWriter csvWriter1 = CsvWriter.builder().build(osw1);
                 OutputStreamWriter osw2 = new OutputStreamWriter(Files.newOutputStream(Paths.get(d2)),
                         StandardCharsets.UTF_8);
                 CsvWriter csvWriter2 = CsvWriter.builder().build(osw2);
                 OutputStreamWriter osw3 = new OutputStreamWriter(Files.newOutputStream(Paths.get(o2)),
                         StandardCharsets.UTF_8);
                 CsvWriter csvWriter3 = CsvWriter.builder().build(osw3);
            ) {
                csvWriter1.writeRow("黑名单号码", "入黑名单原因", "解黑建议", "开始时间", "结束时间", "入黑名单原因", "解黑建议", "开始时间", "结束时间", "命中策略说明", "操作类型", "是否一致", "不一致原因");
                csvWriter3.writeRow("不一致情况", "黑名单号码", "入黑名单原因", "解黑建议", "开始时间", "结束时间", "入黑名单原因", "解黑建议", "开始时间", "结束时间");
                for (Map<String, String> v2 : m2.values()) {
                    String phone = v2.get("phone");
                    Map<String, String> v1 = m1.getOrDefault(phone, new HashMap<>());
                    if (CollectionUtils.isEmpty(v1) && "2".equals(v2.get("operation_type"))) {
                        continue;
                    }

                    String flag = "是";
                    String diff = "";
                    String situation = "";
                    if (!v2.get("reason").equals(v1.get("reason"))) {
                        diff = "入黑名单原因、";
                        situation = "有同步记录但是数据不一致";
                    }
                    if (!v2.get("start_time").equals(v1.get("start_time"))) {
                        diff = diff + "开始时间、";
                        situation = "有同步记录但是数据不一致";
                    }
                    if (!v2.get("end_time").equals(v1.get("end_time"))) {
                        diff = diff + "结束时间、";
                        situation = "有同步记录但是数据不一致";
                    }
                    if (!v2.get("suggestion").equals(v1.get("suggestion"))) {
                        diff = diff + "解黑建议、";
                        situation = "有同步记录但是数据不一致";
                    }
                    if (CollectionUtils.isEmpty(v1)) {
                        diff = "在黑数据中没有记录";
                        situation = "数据库中存在但是在黑数据不存在";
                    }
                    if (StringUtils.hasText(diff)) {
                        flag = "否";
                        csvWriter3.writeRow(situation, phone, v2.get("reason"), v2.get("suggestion"), v2.get("start_time"), v2.get("end_time"), v1.get("reason"), v1.get("suggestion"), v1.get("start_time"), v1.get("end_time"));
                        csvWriter2.writeRow("黑名单号码", "入黑名单原因", "解黑建议", "开始时间", "结束时间", "入黑名单原因", "解黑建议", "开始时间", "结束时间", "命中策略说明", "操作类型", "是否一致", "不一致原因");
                        csvWriter2.writeRow(phone, v2.get("reason"), v2.get("suggestion"), v2.get("start_time"), v2.get("end_time"), v1.get("reason"), v1.get("suggestion"), v1.get("start_time"), v1.get("end_time"), v2.get("hit_desc"), v2.get("operation_type"), flag, diff);
                        csvWriter2.writeRow("黑名单号码", "入黑名单原因", "解黑建议", "开始时间", "结束时间", "命中策略说明", "操作类型", "同步文件名");
                        try (CsvReader csvReader = CsvReader.builder().build(Paths.get(record), StandardCharsets.UTF_8)) {
                            for (CsvRow row : csvReader) {
                                if (row.getOriginalLineNumber() == 1 || !phone.equals(row.getField(0))) {
                                    continue;
                                }
                                csvWriter2.writeRow(
                                        row.getField(0),
                                        row.getField(1),
                                        row.getField(6),
                                        row.getField(2),
                                        row.getField(3),
                                        row.getField(4),
                                        row.getField(5),
                                        row.getField(7)
                                );
                            }
                        }
                        csvWriter2.writeRow();
                    }
                    csvWriter1.writeRow(phone, v1.get("reason"), v1.get("suggestion"), v1.get("start_time"), v1.get("end_time"), v2.get("reason"), v2.get("suggestion"), v2.get("start_time"), v2.get("end_time"), v2.get("hit_desc"), v2.get("operation_type"), flag, diff);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 测试导入数据
     */
    @Test
    void testImport() {
        String path = TEST_DIR + "download";
        // 读取目标文件夹下的文件
        try (Stream<Path> stream = Files.list(Paths.get(path))) {
            List<Path> pathList = stream.collect(Collectors.toList());
            log.info("pathList: {}", pathList);
            for (Path t : pathList) {
                List<Object[]> l1 = new ArrayList<>();
                List<Object[]> l2 = new ArrayList<>();
                log.info("file: {}", t.getFileName().toString());
                try (CsvReader csvReader = CsvReader.builder().build(t, StandardCharsets.UTF_8)) {
                    for (CsvRow row : csvReader) {
                        Object[] o1 = new Object[]{
                                row.getField(0),
                                Integer.valueOf(row.getField(1)),
                                row.getField(2),
                                row.getField(3),
                                row.getField(4),
                                Integer.valueOf(row.getField(5)),
                                Integer.valueOf(row.getField(6)),
                        };
                        l1.add(o1);
                        Object[] o2 = new Object[]{
                                row.getField(0),
                                Integer.valueOf(row.getField(1)),
                                row.getField(2),
                                row.getField(3),
                                row.getField(4),
                                Integer.valueOf(row.getField(5)),
                                Integer.valueOf(row.getField(6)),
                                t.getFileName().toString()
                        };
                        l2.add(o2);
                    }
                }
                log.info("blacklist");
                String sql = "insert into sms_blk.blacklist " +
                        "(phone, reason, start_time, end_time, hit_desc, operation_type, suggestion) " +
                        "values (?, ?, ?, ?, ?, ?, ?) " +
                        "on conflict (phone) " +
                        "do update set (reason, start_time, end_time, hit_desc, operation_type, suggestion) = " +
                        "(excluded.reason, excluded.start_time, excluded.end_time, excluded.hit_desc, " +
                        "excluded.operation_type, excluded.suggestion)";
                jdbcTemplate.batchUpdate(sql, l1);
                log.info("blacklist_file");
                sql = "insert into sms_blk.blacklist_file " +
                        "(phone, reason, start_time, end_time, hit_desc, operation_type, suggestion, filename) " +
                        "values (?, ?, ?, ?, ?, ?, ?, ?)";
                jdbcTemplate.batchUpdate(sql, l2);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    void testUpdate() {
        Set<String> notExists = new HashSet<>();
        try (CsvReader csvReader = CsvReader.builder().build(Paths.get(TEST_DIR + "data1.csv"), StandardCharsets.UTF_8)) {
            for (CsvRow row : csvReader) {
                log.info("{} row: {}", row.getOriginalLineNumber(), row.getFields());
                if (!StringUtils.hasText(row.getField(0))) {
                    log.warn("跳过空行");
                    continue;
                }
                String phone = StringUtils.trimAllWhitespace(row.getField(0));
                Integer reason = Integer.valueOf(StringUtils.trimAllWhitespace(row.getField(1)));
                String startTime = StringUtils.trimAllWhitespace(row.getField(2));
                String endTime = StringUtils.trimAllWhitespace(row.getField(3));
                Integer suggestion = Integer.valueOf(StringUtils.trimAllWhitespace(row.getField(4)));
                log.info("{},{},{},{},{}", phone, reason, startTime, endTime, suggestion);
                String sql = "select * from sms_blk.blacklist where phone = ?";
                Map<String, Object> map = null;
                try {
                    map = jdbcTemplate.queryForMap(sql, phone);
                } catch (EmptyResultDataAccessException e) {
                    log.warn("{} not exist", phone);
                    notExists.add(phone);
                }

                if (!CollectionUtils.isEmpty(map)) {
                    if (startTime.equals(map.get("start_time"))
                            || (Long.parseLong(startTime) > Long.parseLong(map.get("start_time").toString()))) {
                        log.info("map: {}", map);
                        sql = "update sms_blk.blacklist set reason = ?, start_time = ?, end_time = ?, suggestion = ?, operation_type = 1 where phone = ?";
                        jdbcTemplate.update(sql, reason, startTime, endTime, suggestion, phone);
                    }
                }
            }

            log.info("{} notExists: {}", notExists.size(), notExists);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    void testTrimAllWhitespace() {
        String d1 = TEST_DIR + "data.csv";
        String d2 = TEST_DIR + "dataa.csv";
        try (CsvReader csvReader = CsvReader.builder().build(Paths.get(d1), StandardCharsets.UTF_8);
             OutputStreamWriter osw1 = new OutputStreamWriter(Files.newOutputStream(Paths.get(d2)), StandardCharsets.UTF_8);
             CsvWriter csvWriter1 = CsvWriter.builder().build(osw1);
        ) {
            for (CsvRow row : csvReader) {
                if (!StringUtils.hasText(row.getField(0))) {
                    log.warn("跳过空行");
                    continue;
                }
                String phone = StringUtils.trimAllWhitespace(row.getField(0));
                String reason = StringUtils.trimAllWhitespace(row.getField(1));
                String startTime = StringUtils.trimAllWhitespace(row.getField(2));
                String endTime = StringUtils.trimAllWhitespace(row.getField(3));
                String suggestion = StringUtils.trimAllWhitespace(row.getField(4));
                csvWriter1.writeRow(phone, reason, startTime, endTime, suggestion);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
