package com.zfire.mall.manager.logic.k3;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ReUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.nacos.client.utils.JSONUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.zfire.mall.manager.bean.k3.RequestApiBean;
import com.zfire.mall.manager.config.k3.KingDeeUser;
import com.zfire.mall.manager.constant.Constant;
import com.zfire.mall.manager.exception.RemoteServiceException;
import com.zfire.mall.manager.helper.KingDeeInvokeHelper;
import com.zfire.mall.manager.plus.entity.KingDeeInterface;
import com.zfire.mall.manager.plus.entity.KingDeeSyncTask;
import com.zfire.mall.manager.plus.service.KingDeeInterfaceService;
import com.zfire.mall.manager.plus.service.KingDeeSyncTaskService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

@Slf4j
@Service
public class K3Logic {

    @Autowired
    RedisLockRegistry redisLockRegistry;
    @Autowired
    KingDeeSyncTaskService kingDeeSyncTaskService;
    @Resource
    KingDeeInterfaceService kingDeeInterfaceService;

    public <T> List<T> allSync(RequestApiBean requestApiBean, String[] objFields, Class cls) throws Exception {
        // 结果集
        List<T> list = new ArrayList<>();

        String taskId = null;
        try {
            //检查是否允许同步
            taskId = this.checkDistExec(requestApiBean);
            if (taskId == null) {
                throw new RemoteServiceException(requestApiBean.getFormId()+"目前存在同步中的任务，请稍后再试");
            }
            // 登录金蝶
            if (!KingDeeInvokeHelper.Login(KingDeeUser.getDB(), KingDeeUser.getACCOUNT(), KingDeeUser.getPASSWORD(), KingDeeUser.getLANG())) {
                return null;
            }
            final int pageSize = 1000;
            boolean exists = true;
            while (exists) {
                // 返回结果
                log.info("【对接金蝶】request：{}", requestApiBean);
                String result = KingDeeInvokeHelper.ExecuteBillQuery(null, JSONUtils.serializeObject(requestApiBean));
                if (result.equals("[]")) {
                    return null;
                }
//            log.info("【对接金蝶】response：{}", requestApiBean);
                Object[] resultList = JSON.parseArray(result).toArray();
//            this.setKingDeeValue(objFields, resultList, KingDeeMaterial.class);
                for (Object o : resultList) {
                    JSONArray oo = (JSONArray) o;
                    T tObj = this.setKingDeeValue(objFields, oo.toArray(), cls);
                    if (tObj != null)
                        list.add(tObj);
                }
                //判断是否需要多次请求，金蝶默认1次只能拿1000条数据
                if (resultList.length == (requestApiBean.getTopRowCount() - requestApiBean.getStartRow())) {
                    requestApiBean.setTopRowCount(requestApiBean.getTopRowCount() + pageSize);
                    requestApiBean.setStartRow(requestApiBean.getStartRow() + pageSize);
                } else {
                    exists = false;
                }
            }
            if(!requestApiBean.getNotTime()) {
                // 记录最后一同步时间
                kingDeeInterfaceService.lambdaUpdate()
                        .eq(KingDeeInterface::getOrgId, requestApiBean.getOrgId())
                        .eq(KingDeeInterface::getOrgNumber, requestApiBean.getOrgNumber())
                        .eq(KingDeeInterface::getFormId, requestApiBean.getFormId())
                        .set(KingDeeInterface::getSyncLastTime, requestApiBean.getEndTime())
                        .update();
            }
        } finally {
            //不管报错否，都要完成本次任务，不能阻塞后面的运行
            this.updateSyncTask(taskId);
        }
        return list;
    }

    private void updateSyncTask(String taskId) {
        if(StringUtils.isEmpty(taskId)){
            return;
        }
        kingDeeSyncTaskService.lambdaUpdate()
                .set(KingDeeSyncTask::getStatus, 1)
                .set(KingDeeSyncTask::getSyncTime, DateUtil.formatDateTime(new Date()))
                .eq(KingDeeSyncTask::getId,taskId)
                .update();
    }


    /**
     * 检查是否重复执行
     */
    public String checkDistExec(RequestApiBean requestApiBean){
   //     Lock obtain = redisLockRegistry.obtain(Constant.RedisPrefix.LOCK_K3_TASK + requestApiBean.getFormId());
        try {
            //if (obtain.tryLock(5, TimeUnit.SECONDS)) {

                KingDeeInterface kingDeeInterface = kingDeeInterfaceService.lambdaQuery()
                        .eq(KingDeeInterface::getFormId, requestApiBean.getFormId()).one();

                KingDeeSyncTask kingDeeSyncTask = new KingDeeSyncTask();
                kingDeeSyncTask.setOrgId(requestApiBean.getOrgId());
                kingDeeSyncTask.setOrgNumber(requestApiBean.getOrgNumber());
                kingDeeSyncTask.setFormId(requestApiBean.getFormId());
                kingDeeSyncTask.setTaskId(IdWorker.getIdStr());
                if (kingDeeInterface != null) {
                    kingDeeSyncTask.setName(kingDeeInterface.getName());
                }
                if (Objects.nonNull(requestApiBean.getStartTime())) {
                    kingDeeSyncTask.setStartTime(DateUtil.parseDateTime(requestApiBean.getStartTime()));
                }
                if (Objects.nonNull(requestApiBean.getEndTime())) {
                    kingDeeSyncTask.setEndTime(DateUtil.parseDateTime(requestApiBean.getEndTime()));
                }
                kingDeeSyncTask.setType(requestApiBean.getFormType());
                kingDeeSyncTask.insert();

                return kingDeeSyncTask.getId();

                //return count == 0;
        //    }
        } catch (Exception e) {
            log.error("【金蝶】检查是否重复执行失败", e);
        } finally {
    //        obtain.unlock();
        }
        return null;
    }

    /**
     * 检查是否重复执行
     */
    public String checkDistNoLockExec(RequestApiBean requestApiBean, String type) {
        KingDeeInterface kingDeeInterface = kingDeeInterfaceService.lambdaQuery().eq(KingDeeInterface::getFormId, requestApiBean.getFormId()).one();

        Integer count = kingDeeSyncTaskService.lambdaQuery()
                .eq(KingDeeSyncTask::getFormId, requestApiBean.getFormId())
                .eq(KingDeeSyncTask::getStatus, 0).count();
        if (count == 0) {
            KingDeeSyncTask kingDeeSyncTask = new KingDeeSyncTask();
            kingDeeSyncTask.setOrgId(requestApiBean.getOrgId());
            kingDeeSyncTask.setOrgNumber(requestApiBean.getOrgNumber());
            kingDeeSyncTask.setFormId(requestApiBean.getFormId());
            kingDeeSyncTask.setTaskId(IdUtil.simpleUUID());
            kingDeeSyncTask.setName(kingDeeInterface.getName());
            if (Objects.nonNull(requestApiBean.getStartTime())) {
                kingDeeSyncTask.setStartTime(DateUtil.parseDateTime(requestApiBean.getStartTime()));
            }
            if (Objects.nonNull(requestApiBean.getEndTime())) {
                kingDeeSyncTask.setEndTime(DateUtil.parseDateTime(requestApiBean.getEndTime()));
            }
            kingDeeSyncTask.setType(requestApiBean.getFormType());
            kingDeeSyncTask.insert();
            return kingDeeSyncTask.getId();
        }

        return null;
    }

    /**
     * 通过java反射机制赋值
     *
     * @param fileds
     * @param attrs
     * @param cls
     * @param <T>
     * @return
     */
    public <T> T setKingDeeValue(String[] fileds, Object attrs[], Class cls) {
        if (fileds.length == 0 || fileds.length != attrs.length) {
            return null;
        }
        try {
            Object obj = cls.newInstance();
            for (int i = 0; i < fileds.length; i++) {
                Field declaredField = cls.getDeclaredField(fileds[i]);
                declaredField.setAccessible(true);
                if (attrs[i] == null) {
                    declaredField.set(obj, null);
                    continue;
                }
                if (attrs[i] instanceof Date) {
                    declaredField.set(obj, attrs[i]);
                } else if (ReUtil.contains("^([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]|[0-9][1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8])))T", attrs[i].toString())) {
                    LocalDateTime localDateTime = LocalDateTime.parse(attrs[i].toString());
                    ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
                    // 本地时间线LocalDateTime到即时时间线Instant时间戳
                    Instant instant = zonedDateTime.toInstant();
                    // UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
                    Date date = Date.from(instant);
                    declaredField.set(obj, date);
                } else if (attrs[i] instanceof BigDecimal) {
                    declaredField.set(obj, attrs[i]);
                } else if (attrs[i] instanceof Boolean) {
                    declaredField.set(obj, attrs[i]);
                } else {
                    if (attrs[i] == null)
                        declaredField.set(obj, attrs[i]);
                    else
                        declaredField.set(obj, attrs[i].toString());
                }
            }
            //同步时间 sync_time
            Field declaredField = cls.getDeclaredField("syncTime");
            declaredField.setAccessible(true);
            declaredField.set(obj, new Date());

            return (T) obj;
        } catch (Exception e) {
            log.error("set field error", e);
            return null;
        }
    }

    public RequestApiBean getInstance(String orgId, String orgNumber, String formId, String startTime, String
            endTime) {

        RequestApiBean request = new RequestApiBean();
        request.setOrgId(orgId);
        request.setOrgNumber(orgNumber);
        request.setFormId(formId);
        if (StringUtils.isEmpty(startTime)) {

            KingDeeInterface kingDeeInterface = kingDeeInterfaceService.lambdaQuery()
                    .eq(StringUtils.isNotEmpty(orgNumber), KingDeeInterface::getOrgNumber, orgNumber)
                    .eq(KingDeeInterface::getFormId, formId)
                    .one();
            if (kingDeeInterface != null) {
                startTime = kingDeeInterface.getSyncLastTime().trim();
            }

            if (StringUtils.isEmpty(startTime)) {
                startTime = "1990-01-01 00:00:00";
            }
        }
        if (StringUtils.isEmpty(endTime)) {
            endTime = DateUtil.formatDateTime(new Date());
        }
        request.setStartTime(startTime);
        request.setEndTime(endTime);
        return request;
    }


    public String supplySql(String startTime, String endTime) {
        return this.supplySql("FApproveDate", startTime, endTime);
    }


    public String supplySql(String commonQueryDateStr, String startTime, String endTime) {
        return this.supplySql(commonQueryDateStr, startTime, endTime, true);
    }

    public String supplySql(String commonQueryDateStr, String startTime, String endTime, Boolean joinWhere) {
        String and = "";
        if (joinWhere) {
            and = " AND ";
        }
        if (StringUtils.isNotEmpty(startTime) && StringUtils.isNotEmpty(endTime)) {
            return String.format(and + commonQueryDateStr + " > '%s' AND " + commonQueryDateStr + " <= '%s'", startTime, endTime);
        }
        if (StringUtils.isNotEmpty(endTime)) {
            return String.format(and + commonQueryDateStr + " <= '%s'", endTime);
        }
        return "";
    }


    public <T> List<T> allNoLockSync(RequestApiBean requestApiBean, String type, String[] objFields, Class cls) throws
            Exception {
        //检查是否允许同步
        String taskId = this.checkDistNoLockExec(requestApiBean, type);

        // 登录金蝶
        if (!KingDeeInvokeHelper.Login(KingDeeUser.getDB(), KingDeeUser.getACCOUNT(), KingDeeUser.getPASSWORD(), KingDeeUser.getLANG())) {
            return null;
        }
        // 结果集
        List<T> list = new ArrayList<>();

        final int pageSize = 1000;
        boolean exists = true;
        while (exists) {
            // 返回结果
            log.info("【对接金蝶】request：{}", requestApiBean);
            String result = KingDeeInvokeHelper.ExecuteBillQuery(null, JSONUtils.serializeObject(requestApiBean));
            if (result.equals("[]")) {
                this.updateSyncTask(taskId);
                return null;
            }
//            log.info("【对接金蝶】response：{}", requestApiBean);
            Object[] resultList = JSON.parseArray(result).toArray();
//            this.setKingDeeValue(objFields, resultList, KingDeeMaterial.class);
            for (Object o : resultList) {
                JSONArray oo = (JSONArray) o;
                T tObj = this.setKingDeeValue(objFields, oo.toArray(), cls);
                list.add(tObj);
            }
            //判断是否需要多次请求，金蝶默认1次只能拿1000条数据
            if (resultList.length == (requestApiBean.getTopRowCount() - requestApiBean.getStartRow())) {
                requestApiBean.setTopRowCount(requestApiBean.getTopRowCount() + pageSize);
                requestApiBean.setStartRow(requestApiBean.getStartRow() + pageSize);
            } else {
                exists = false;
            }
        }

        return list;
    }
}
