package com.brilliance.isc.common.oit.service.impl;


import com.alibaba.fastjson2.JSON;
import org.springframework.util.ObjectUtils;
import com.brilliance.isc.annotation.OitByObjectInr;
import com.brilliance.isc.annotation.OitCommon;
import com.brilliance.isc.common.oit.service.OitService;
import com.brilliance.isc.common.oit.service.OitenTryService;
import com.brilliance.isc.common.oit.vo.NoticeVo;
import com.brilliance.isc.constant.LimCons;
import com.brilliance.isc.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.*;

@Slf4j
@Service
public class OitenTryServiceImpl implements OitenTryService {
    private ThreadLocal <List<NoticeVo>> noticeVos =  new ThreadLocal(){
        @Override
        protected List<NoticeVo> initialValue() {
            return new ArrayList<>();
        }
    };

    @Autowired
    private OitService oitService;
    /**
     * 递归深度
     */
    private final int SCAN_COUNT = 5;
    private final String POINT = ".";

    /**
     * 收集需要通知的实体并给出通知
     *
     * @param entity
     * @return
     */
    public List<Map<String,Object>> collectEntitiesAndNotice(Object entity) {
        noticeVos.remove();

        scanOit(entity, 0, "");
        log.info("通知列表为：{}", JSON.toJSONString(noticeVos.get()));
        oitService.queryOitMessage(noticeVos.get(), LimCons.OIT_TYPE_SAVE);
        return oitService.huoquErrorMaps();
    }

    /**
     * 扫描需要通知的实体
     *
     * @param entity
     * @param executecount
     */
    void scanOit(Object entity, int executecount, String path) {
        executecount++;

        if (ObjectUtils.isEmpty(entity)) {
            return;
        }
        log.debug("-------------------------------------------:{}{}", entity.getClass().getName(), executecount);
        if (executecount > SCAN_COUNT) {
            return;
        }
        try {
            Class clazz = entity.getClass();
            //通过objinr确认通知内容
            OitByObjectInr oitByObjectInr = (OitByObjectInr) clazz.getDeclaredAnnotation(OitByObjectInr.class);
            if (!ObjectUtils.isEmpty(oitByObjectInr)) {
                if (!ObjectUtils.isEmpty(oitByObjectInr.objtype())) {
                    log.info("命中oit by objinr{}", clazz.getName());
                    String objtyp = oitByObjectInr.objtype();
                    Field subobjinrfield = clazz.getDeclaredField(oitByObjectInr.objinrnam());
                    subobjinrfield.setAccessible(true);
                    String objinr = (String) subobjinrfield.get(entity);
                    if (StringUtils.isEmpty(objinr)) {
                        return;
                    }
                    addNoticeByObjinr(objtyp, objinr, StringUtils.stringAppend(path, POINT, subobjinrfield.getName()));
                }
            }
            //通过查询业务表唯一字段确认通知内容
            OitCommon oitCommon = (OitCommon) clazz.getDeclaredAnnotation(OitCommon.class);
            if (!ObjectUtils.isEmpty(oitCommon)) {
                if (!ObjectUtils.isEmpty(oitCommon.objtype())) {
                    log.info("命中oit by extkey {}", clazz.getName());
                    String objtyp = oitCommon.objtype();
                    Field subobjinrfield = clazz.getDeclaredField(oitCommon.extkeyfield());
                    subobjinrfield.setAccessible(true);
                    String extkey = (String) subobjinrfield.get(entity);
                    if (StringUtils.isEmpty(extkey)) {
                        return;
                    }
                    addNoticeByExtkey(objtyp, extkey, StringUtils.stringAppend(path, POINT, subobjinrfield.getName()), oitCommon.column());
                }
            }

            List<Field> fields = getSuperFields(clazz);
            for (Field field : fields) {
                log.debug("------{}-------", field.getName());
                String fieldpath = "";
                if (executecount > 1) {
                    fieldpath = StringUtils.stringAppend(path, POINT, field.getName());
                } else {
                    fieldpath = field.getName();
                }
                field.setAccessible(true);
                Object fieldinstance = field.get(entity);
                if (fieldinstance == null) {
                    continue;
                }
                if (fieldinstance instanceof String) {
                    continue;
                } else if (fieldinstance instanceof Integer) {
                    continue;
                } else if (fieldinstance instanceof BigDecimal) {
                    continue;
                } else if (fieldinstance instanceof Date) {
                    continue;
                } else if (fieldinstance instanceof java.sql.Date) {
                    continue;
                } else {
                    if (fieldinstance instanceof List) {
                        int index = 0;
                        for (Object objfield : ((List) fieldinstance)) {
                            String objfieldpath = StringUtils.stringAppend(fieldpath, POINT, String.valueOf(index++));
                            scanOit(objfield, executecount, objfieldpath);
                        }
                    } else {

                        scanOit(fieldinstance, executecount, fieldpath);
                    }
                }

            }
        } catch (IllegalAccessException e) {
            log.error("通知实体扫描异常{}", e.getMessage());
        } catch (NoSuchFieldException e) {
            log.error("通知实体扫描异常{}", e.getCause().getMessage());
        }
        log.debug("------------------------------------------------------");
        log.debug("通知列表为： {}", JSON.toJSONString(noticeVos));
    }

    public static List<Field> getSuperFields(Class<?> clzss) {
        List<Field> fieldList = new ArrayList<>();
        //取父类属性
        while (clzss != null) {
            fieldList.addAll(Arrays.asList(clzss.getDeclaredFields())); //添加当前类全部属性
            // 父类
            clzss = clzss.getSuperclass();
        }
        return fieldList;
    }

    void addNoticeByObjinr(String objtyp, String objinr, String path) {
        NoticeVo noticeVo = new NoticeVo();
        noticeVo.setObjtyp(objtyp);
        noticeVo.setObjinr(objinr);
        noticeVo.setPath(path);
        noticeVos.get().add(noticeVo);
    }

    void addNoticeByExtkey(String objtyp, String extkey, String path, String column) {
        NoticeVo noticeVo = new NoticeVo();
        noticeVo.setObjtyp(objtyp);
        noticeVo.setExtkey(extkey);
        noticeVo.setColumn(column);
        noticeVo.setPath(path);
        noticeVos.get().add(noticeVo);
    }

}
