import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson2.JSONObject;
import com.chushang.InspectionApplication;
import com.chushang.inspection.terminal.po.Store;
import com.chushang.inspection.terminal.po.Terminal;
import com.chushang.inspection.terminal.po.TerminalIns;
import com.chushang.inspection.terminal.service.StoreService;
import com.chushang.inspection.terminal.service.TerminalInsService;
import com.chushang.inspection.terminal.service.TerminalService;
import com.chushang.inspection.work.po.*;
import com.chushang.inspection.work.service.*;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import po.Column;
import po.WrkInfoEntity;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.sql.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest(classes = InspectionApplication.class)
public class JsIcbcTest {
    @Resource
    private WrkIcbcJsService wrkIcbcJsService;
    @Resource
    TerminalService terminalService;
    @Resource
    StoreService storeService;
    @Resource
    TerminalInsService terminalInsService;

    @Resource
    WrkInfoService wrkInfoService;
    @Resource
    WrkInfoStoreRecordService storeRecordService;
    @Resource
    WrkInfoTerminalRecordService terminalRecordService;
    @Resource
    WrkInfoTerminalInsRecordService terminalInsRecordService;

    private WrkIcbcJs update(WrkIcbcJs w, JSONObject terJson, Store store) {
        Terminal terminal = terJson.getObject("terminal", Terminal.class);
        // 江苏工行实体类信息
        WrkIcbcJs wrkIcbcJs = new WrkIcbcJs();
        wrkIcbcJs.setStoreId(store.getStoreId());
        wrkIcbcJs.setTerminalId(terminal.getTerminalId());
        wrkIcbcJs.setId(w.getId());
        wrkIcbcJsService.updateById(wrkIcbcJs);
        return wrkIcbcJs;
    }

    @Test
    public void jsWrkTest() {
        // JDBC连接URL
        String url = "jdbc:mariadb://119.97.184.98:3306/work_inspection?serverTimezone=GMT%2B8&characterEncoding=utf8&useSSL=false&autoReconnect=true&failOverReadOnly=false&rewriteBatchedStatements=true";
        String username = "inspection";
        String password = "qq630638001";
        List<WrkIcbcJs> list = wrkIcbcJsService.list();
        mergeJsIcbc(list);

        Map<Long, WrkInfo> wrkInfos = new HashMap<>();
        Map<Long, WrkInfoStoreRecord> storeRecords = new HashMap<>();
        Map<Long, WrkInfoTerminalRecord> terminalRecords = new HashMap<>();
        Map<Long, WrkInfoTerminalInsRecord> terminalInsRecords = new HashMap<>();
        try {
            // 创建数据库连接
            Connection conn = DriverManager.getConnection(url, username, password);
            String collect = list.stream()
                    .filter(w -> null != w.getWrkId()).map(w -> String.valueOf(w.getWrkId()))
                    .collect(Collectors.joining(","));

            Map<Long, WrkIcbcJs> jsMap = list.stream()
                    .filter(w -> null != w.getWrkId()).collect(Collectors.toMap(
                            WrkIcbcJs::getWrkId,
                            w -> w,
                            (o, n) -> n
                    ));


            String selectSql = "SELECT * FROM wrk_info WHERE id in ( " + collect + ")";
            PreparedStatement pstmt = conn.prepareStatement(selectSql);
            List<WrkInfoEntity> wrkInfoEntitys = convertToList(pstmt.executeQuery(), WrkInfoEntity.class);
            for (WrkInfoEntity wrkInfoEntity : wrkInfoEntitys) {
                Long wrkId = wrkInfoEntity.getId();
                if (null == wrkId) continue;
                WrkIcbcJs wrkIcbcJs = jsMap.get(wrkId);
                Store store = storeService.getById(wrkIcbcJs.getStoreId());
                Terminal terminal = terminalService.getById(wrkIcbcJs.getTerminalId());
                TerminalIns terminalIns = terminalInsService.getById(terminal.getTerminalId());
                terminal.setTerminalId(wrkIcbcJs.getTerminalId());
                terminal.setTerminalStatus(wrkInfoEntity.getTerminalStatus());
                terminal.setOccupy(wrkInfoEntity.getState() == 1 ? 1 : 0);
                terminal.setTerminalModel(wrkInfoEntity.getTerminalModel());
                terminal.setTerminalAddress(wrkInfoEntity.getTerminalAddress());
                terminal.setTerminalSource(wrkInfoEntity.getTerminalSource());
                terminal.setTerminalVersion(wrkInfoEntity.getTerminalVersion());

                store.setState(wrkInfoEntity.getStoreStatus());
                store.setInsFre(wrkInfoEntity.getInsFre());
                store.setSpecialNum(wrkInfoEntity.getSpecialNum());
                store.setShopName(wrkInfoEntity.getShopName());
                store.setStoreName(wrkInfoEntity.getName());
                store.setStoreType(wrkInfoEntity.getType());
                store.setProducts(wrkInfoEntity.getProducts());
                store.setAccountManager(wrkInfoEntity.getAccountManager());
                store.setAccountPhone(wrkInfoEntity.getAccountPhone());
                store.setRegisterTime(null != wrkInfoEntity.getRegisterTime() ? wrkInfoEntity.getRegisterTime().atStartOfDay() : null);
                store.setRegisterAddress(wrkInfoEntity.getRegisterAddress());

                terminalIns.setTerminalId(wrkIcbcJs.getTerminalId());
                terminalIns.setServiceResult(wrkInfoEntity.getServiceResult());
                terminalIns.setIsEnter(2);
                terminalIns.setDeviation(wrkInfoEntity.getDeviation());
                terminalIns.setPreCodeEncoding(wrkInfoEntity.getPrecodeEncoding());
                terminalIns.setInspectionStatus(1);
                terminalIns.setInspectionTime(wrkInfoEntity.getDisposeTime());
                terminalIns.setOperatorId(String.valueOf(wrkInfoEntity.getUserId()));
                terminalIns.setWorkAddress(wrkInfoEntity.getWorkAdderss());
                terminalIns.setWorkLocation(wrkInfoEntity.getWorkLocation());
                terminalIns.setGeographicAddress(wrkInfoEntity.getLocationAddress());
                terminalIns.setGeographicLocation(wrkInfoEntity.getGeographicLocation());

                updateStoreAndTer(store, terminal, terminalIns);

                WrkInfo wrkInfo = getWrkInfo(wrkInfoEntity);
                wrkInfo.setProjectId(store.getProjectId());
                wrkInfo.setDeptId(store.getDeptId());

                WrkInfoStoreRecord wrkInfoStoreRecord = BeanUtil.copyProperties(store, WrkInfoStoreRecord.class);
                wrkInfoStoreRecord.setWrkId(wrkInfoEntity.getId());
                wrkInfoStoreRecord.setProjectId(store.getProjectId());

                WrkInfoTerminalRecord wrkInfoTerminalRecord = BeanUtil.copyProperties(terminal, WrkInfoTerminalRecord.class);
                wrkInfoTerminalRecord.setWrkId(wrkInfo.getWrkId());
                wrkInfoTerminalRecord.setProjectId(store.getProjectId());
                WrkInfoTerminalInsRecord wrkInfoTerminalInsRecord = BeanUtil.copyProperties(terminalIns, WrkInfoTerminalInsRecord.class);
                wrkInfoTerminalInsRecord.setWrkId(wrkInfo.getWrkId());

                saveWrk(wrkInfo, wrkInfoStoreRecord, wrkInfoTerminalRecord, wrkInfoTerminalInsRecord);

                wrkInfos.put(wrkId, wrkInfo);
                storeRecords.put(wrkId, wrkInfoStoreRecord);
                terminalRecords.put(wrkId, wrkInfoTerminalRecord);
                terminalInsRecords.put(wrkId, wrkInfoTerminalInsRecord);

            }

            conn.close();
            // 关闭连接
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.info("wrk {}", wrkInfos.size());
        log.info("storeRecords {}", storeRecords.size());
        log.info("terminalRecords {}", terminalRecords.size());
        log.info("terminalInsRecords {}", terminalInsRecords.size());


    }

    public void saveWrk(WrkInfo wrkInfo, WrkInfoStoreRecord wrkInfoStoreRecord, WrkInfoTerminalRecord wrkInfoTerminalRecord, WrkInfoTerminalInsRecord wrkInfoTerminalInsRecord) {
        wrkInfoService.save(wrkInfo);
        storeRecordService.save(wrkInfoStoreRecord);
        terminalRecordService.save(wrkInfoTerminalRecord);
        terminalInsRecordService.save(wrkInfoTerminalInsRecord);
    }

    public void mergeJsIcbc(List<WrkIcbcJs> list) {
        for (WrkIcbcJs w : list) {
            Store store = storeService.saveJcIcbc(w);
            JSONObject save = terminalService.save(store, w);
            update(w, save, store);
        }
    }

    public void updateStoreAndTer(Store store, Terminal terminal, TerminalIns terminalIns) {
        storeService.updateById(store);
        terminalService.updateById(terminal);
        terminalInsService.updateById(terminalIns);
    }

    public WrkInfo getWrkInfo(WrkInfoEntity wrkInfoEntity) {
        WrkInfo wrkInfo = new WrkInfo();
        wrkInfo.setWrkId(wrkInfoEntity.getId());
        wrkInfo.setWorkNo(wrkInfoEntity.getWorkNo());
        wrkInfo.setWorkType(wrkInfoEntity.getWorkType());
        wrkInfo.setWorkSource(wrkInfoEntity.getWorkSource());
        wrkInfo.setWorkMethod(wrkInfoEntity.getWorkMethod());
        wrkInfo.setWorkSort(wrkInfoEntity.getWorkSort());
        wrkInfo.setDisposeTime(wrkInfoEntity.getDisposeTime());
        wrkInfo.setAccountManager(wrkInfoEntity.getAccountManager());
        wrkInfo.setAccountPhone(wrkInfoEntity.getAccountPhone());
        wrkInfo.setServiceResult(wrkInfoEntity.getServiceResult());
        wrkInfo.setRemark(wrkInfo.getRemark());
        wrkInfo.setEndTime(wrkInfoEntity.getEndTime());
        //
        Integer state = wrkInfoEntity.getState();
        wrkInfo.setWrkStatus(state == 3 ? 7 : state);
        wrkInfo.setRegisterTime(wrkInfoEntity.getRegisterTime());
        wrkInfo.setDisSchedule(wrkInfo.getDisSchedule());
        wrkInfo.setUserId(wrkInfoEntity.getUserId());
        wrkInfo.setUserName(wrkInfoEntity.getWorkName());
        wrkInfo.setTaskId(wrkInfoEntity.getTaskId());
        wrkInfo.setLowerTaskId(wrkInfoEntity.getLowerTaskId());
        return wrkInfo;
    }

    private static final Pattern UNDERLINE_PATTERN = Pattern.compile("_([a-z])");

    /**
     * 字符串转换为驼峰命名
     *
     * @param str
     * @return
     */
    public static String underlineToHump(String str) {
        //正则匹配下划线及后一个字符，删除下划线并将匹配的字符转成大写
        Matcher matcher = UNDERLINE_PATTERN.matcher(str);
        StringBuilder sb = new StringBuilder(str);
        if (matcher.find()) {
            sb = new StringBuilder();
            //将当前匹配的子串替换成指定字符串，并且将替换后的子串及之前到上次匹配的子串之后的字符串添加到StringBuffer对象中
            //正则之前的字符和被替换的字符
            matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
            //把之后的字符串也添加到StringBuffer对象中
            matcher.appendTail(sb);
        } else {
            //去除除字母之外的前面带的下划线
            return sb.toString().replaceAll("_", "");
        }
        return underlineToHump(sb.toString());
    }


    public static <T> T convertToTarget(ResultSet rs, Class clazz) throws SQLException, InstantiationException, IllegalAccessException {
        //结果集的元素对象
        ResultSetMetaData rsmd = rs.getMetaData();
        //获取结果集的元素个数
        int colCount = rsmd.getColumnCount();
        //业务对象的属性数组
        Field[] fields = clazz.getDeclaredFields();
        T obj = (T) clazz.newInstance();//构造业务对象实体
        //将每一个字段取出进行赋值
        for (int i = 1; i <= colCount; i++) {
            boolean match = false;
            //寻找该列对应的对象属性
            for (int j = 0; j < fields.length; j++) {
                Field field = fields[j];
                //查看是否有注解，有则根据注解中的名称来匹配
                if (field.isAnnotationPresent(Column.class)) {
                    Column column = field.getAnnotation(Column.class);
                    if (column.ignore()) {
                        break;
                    }
                    String columnName = column.value();
                    String columnNameOfSql = rsmd.getColumnName(i);
                    if (columnName.equalsIgnoreCase(columnNameOfSql) && columnNameOfSql != null) {
                        match = true;
                    }
                }
                //如果匹配进行赋值,匹配时，将数据库的列名称转换为驼峰命名法再比较
                else if (field.getName().equalsIgnoreCase(underlineToHump(rsmd.getColumnName(i)))) {
                    match = true;
                }
                if (match) {
                    boolean flag = field.isAccessible();
                    //通过类型获取属性值
                    Class<?> type = field.getType();
                    Object value = rs.getObject(i, type);
                    //直接获取会使jdbc将数据库中的int直接转化为Long类型，导致类型赋值错误
                    //Object value = rs.getObject(i);
                    field.setAccessible(true);
                    field.set(obj, value);
                    field.setAccessible(flag);
                    break;
                }
            }
        }
        return obj;
    }

    /**
     * 将rs结果转换成对象列表
     *
     * @param rs    jdbc结果集
     * @param clazz 对象的映射类
     *              return 封装了对象的结果列表
     */
    public static <T> List<T> convertToList(ResultSet rs, Class clazz) throws SQLException, InstantiationException, IllegalAccessException {
        //返回结果的列表集合
        List list = new ArrayList();
        //对每一条记录进行操作
        while (rs.next()) {
            T obj = convertToTarget(rs, clazz);
            list.add(obj);
        }
        return list;
    }


}
