package com.kingdee.eas.custom.synctask;

import com.kingdee.bos.dao.IObjectPK;
import com.kingdee.bos.metadata.entity.EntityViewInfo;
import com.kingdee.bos.metadata.entity.FilterInfo;
import com.kingdee.bos.metadata.entity.FilterItemInfo;
import com.kingdee.bos.metadata.entity.SelectorItemInfo;
import com.kingdee.bos.metadata.query.util.CompareType;
import com.kingdee.eas.base.permission.UserInfo;
import com.kingdee.eas.basedata.person.PersonCollection;
import com.kingdee.eas.basedata.person.PersonInfo;
import com.kingdee.eas.common.EASBizException;
import com.kingdee.eas.custom.synctask.util.HttpClientUtil;
import com.kingdee.eas.hr.ats.*;
import com.kingdee.eas.hr.ats.holidayLimit.generate.util.HRTimeWebUtils;

import org.apache.log4j.Logger;
import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import com.kingdee.bos.*;
import com.kingdee.eas.basedata.person.IPerson;
import com.kingdee.eas.basedata.person.PersonFactory;
import com.kingdee.eas.framework.CoreBaseCollection;
import com.kingdee.util.StringUtils;

import oadd.org.apache.commons.codec.digest.DigestUtils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;

public class SyncTranForAtsFacadeControllerBean extends AbstractSyncTranForAtsFacadeControllerBean
{
    private static Logger logger =  Logger.getLogger(SyncTranForAtsFacadeControllerBean.class);

    private volatile Properties propt;  // 使用 volatile 保证可见性
    private final Object configLock = new Object();

    private void loadProperties() throws BOSException {
        if (propt == null) {  // 第一次检查
            synchronized (configLock) {
                if (propt == null) {  // 第二次检查（双重检查锁）
                    Properties temp = new Properties();
                    String path = System.getProperty("EAS_HOME") + "/server/properties/abk/syncAtsConfig.properties";
                    try (FileInputStream fis = new FileInputStream(path)) {  // try-with-resources 自动关闭流
                        temp.load(fis);
                        propt = temp;  // 原子性赋值
                    } catch (IOException e) {
                        String errorMsg = "加载配置文件失败: " + path + " | " + e.getMessage();
                        logger.error(errorMsg, e);  // 使用日志记录代替 e.printStackTrace()
                        throw new BOSException(errorMsg);
                    }
                }
            }
        }
    }

    @Override
    protected void _syncPunchRecord(Context ctx, String beginDate, String endDate, int offset) throws BOSException {
        loadProperties();
        // 0. 参数校验与日期解析
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate start = LocalDate.now();
        LocalDate end = LocalDate.now();
        //如果时间参数都为空,则使用offset参数
        if(StringUtils.isEmpty(beginDate) && StringUtils.isEmpty(endDate)){
            if( offset > 0 ){
                //eDate增加offset天
                end = end.plusDays(offset);
            }else if( offset < 0 ) {
                start = start.plusDays(offset);
            }
        }
        if(!StringUtils.isEmpty(beginDate) ){
            //开始日期字定义,结束日期都是今天
            start = LocalDate.parse(beginDate, dateFormatter);
        }
        if(!StringUtils.isEmpty(endDate)){
            //开始日期,结束日期都是今天
            end = LocalDate.parse(endDate, dateFormatter);
        }
        if (start.isAfter(end)) {
            throw new BOSException("开始日期不能晚于结束日期");
        }

        // 1. 按天循环处理
        LocalDate currentDay = start;
        logger.error("startDate:"+currentDay +",enddate:"+end );
        while (!currentDay.isAfter(end)) {
            try {
                // 当天日期字符串
                String dayStr = currentDay.format(dateFormatter);

                // 生成 Token 和 URL 参数
                long currentTime = Instant.now().getEpochSecond();
                String secretKey = propt.getProperty("SECRET_KEY");
                String token = DigestUtils.md5Hex(secretKey + currentTime);
                // 构建查询参数
                Map<String, String> queryParams = new HashMap<>();
//                queryParams.put("timestamp", String.valueOf(currentTime));
//                queryParams.put("token", token);
                //20250717 改用静态
                queryParams.put("key", secretKey);

                // 构建请求体（自动处理时间范围）
                JSONObject requestBody = buildRequestParams(dayStr, dayStr); // 同一天

                // 调用接口
                String urlPath = propt.getProperty("urlPath");
                String response = HttpClientUtil.sendPostRequest(urlPath, requestBody, queryParams);

                // 处理响应
                if (response != null) {
                    JSONObject result = JSONObject.parseObject(response);
                    if ("0".equals(result.getString("ret"))) {
                        JSONObject data = result.getJSONObject("data");
                        JSONArray items = data.getJSONArray("items");
                        logger.error("日期 " + dayStr + " 打卡同步接口,接口共传输记录数: " + items.size()+"条数据");
                        saveMJPunchCardData(ctx, items);
                    }else {
                        System.out.print("打卡，考勤，接口获取错误！");
                    }
                }
            } catch (Exception e) {
                // 记录错误但继续执行
                logger.error("日期 " + currentDay + " 数据同步失败: " + e.getMessage(), e);
            } finally {
                currentDay = currentDay.plusDays(1); // 处理下一天
            }
        }
    }





    private JSONObject buildRequestParams(String startDate, String endDate) {
        JSONObject params = new JSONObject();
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        DateTimeFormatter datetimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        LocalDate today = LocalDate.now();
        // 处理 startDate：默认为当天 00:00:00
        if (StringUtils.isEmpty(startDate)) {
            startDate = today.atStartOfDay().format(datetimeFormatter);
        } else {
            startDate = LocalDate.parse(startDate, dateFormatter)
                    .atStartOfDay()
                    .format(datetimeFormatter);
        }

        // 处理 endDate：默认为当天 23:59:59
        if (StringUtils.isEmpty(endDate)) {
            endDate = today.atTime(23, 59, 59).format(datetimeFormatter);
        } else {
            endDate = LocalDate.parse(endDate, dateFormatter)
                    .atTime(23, 59, 59)
                    .format(datetimeFormatter);
        }
        params.put("starttime", startDate);
        params.put("endtime", endDate);
        return params;
    }




    /**
     * 保存门禁打卡记录
     * @param ctx
     * @param jsonArray
     */
    public void saveMJPunchCardData(Context ctx, JSONArray jsonArray) {
        logger.error("saveMJPunchCardData----");
        try {
            int success = 0;
            Set<String> setCardId = new HashSet();

            CoreBaseCollection cardColl = new CoreBaseCollection();
            //没有考勤档案的人员数据

            //获取员工编码
            IPerson iPerson = PersonFactory.getLocalInstance(ctx);
            PersonCollection personCollection = iPerson.getPersonCollection("select number ,id ");
            Set<String> persNoSet = new HashSet();
            HashMap<String,PersonInfo> persInfoMap = new HashMap();
            for (int i = 0; i < personCollection.size(); i++) {
                PersonInfo personInfo = personCollection.get(i);
                persNoSet.add(personInfo.getNumber().toString());
                persInfoMap.put(personInfo.getNumber().toString(),personInfo);
            }

            //"id": 928547,
            //				"pin": "1234",
            //				"ename": "何霞兰",
            //				"deptnumber": "1",
            //				"deptname": "总部门",
            //				"checktime": "2025-04-25 00:00:12",
            //				"sn": "FAC1234701127",
            //				"alias": "惠州1号楼1层",
            //				"verify": 15,
            //				"stateno": "5",
            //				"state": ""

            //查询本此打卡机过来的数据的id
            HashSet<String> attIds = new HashSet();
            for (int j = 0; j < jsonArray.size(); j++) {
                JSONObject resultData = jsonArray.getJSONObject(j);
                attIds.add(resultData.get("id").toString());
            }

            //相同的数据
            HashSet<String> existedPunchCardRecordCol = getExistedPunchCardRecordCol(ctx, attIds);
            for (int j = 0; j < jsonArray.size(); j++) {
                JSONObject resultData = jsonArray.getJSONObject(j);
                String attId = resultData.getString("id");
                if (existedPunchCardRecordCol.contains(attId)) {
                    continue;
                }
                ++success;
                String personNumber = resultData.getString("pin");//员工编码
                String checktime = resultData.getString("checktime"); //打卡时间
                String RecDate = checktime.substring(0, 10);// 考勤日期
                String address = resultData.getString("alias"); //打卡地点
                String EquNo = resultData.getString("sn"); //考勤机编码
                SimpleDateFormat sdfymd = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date punchDate = sdfymd.parse(RecDate + " 00:00:00");
//                Date punchDate = HRTimeWebUtils.stringToShortDate(RecDate, true);
                Timestamp punchCardTime = HRTimeWebUtils.stringToTimestamp(checktime, true);
                // 处理数据
                if (punchDate != null && punchCardTime != null) {
                    PunchCardRecordInfo cardInfo = new PunchCardRecordInfo();
                    PunchCardRecordCollection punchCardRecordCollection = PunchCardRecordFactory.getLocalInstance(ctx).getPunchCardRecordCollection("where number = '"+attId+"'");
                    if(punchCardRecordCollection.size()>0) {
                        cardInfo = punchCardRecordCollection.get(0);
                    }
                    cardInfo.setNumber(attId);
                    //考勤机编码
                    cardInfo.setEquipmentNum(EquNo);
                    //员工编码
                    //cardInfo.setAttendanceNum(personNumber);
                    //打卡日期
                    cardInfo.setPunchCardDate(punchDate);
                    //打卡时间
                    cardInfo.setPunchCardTime(punchCardTime);
                    // 打卡来源
                    cardInfo.setPunchCardSource(PunchCardSourceEnum.attenceMachine);
                    // 打卡位置
                    cardInfo.setPunchCardPlace(address);
                    // 有效
                    PunchCardStateEnum punchCardStateEnum;
                    //if ((boolean) resultData.get("isActive")) {
                    //    punchCardStateEnum = PunchCardStateEnum.normal;
                    //} else {
                    //    punchCardStateEnum = PunchCardStateEnum.cancelled;
                    //}
                    punchCardStateEnum = PunchCardStateEnum.normal;
                    cardInfo.setPunchCardState(punchCardStateEnum);
                    ////简称
                    //cardInfo.setSimpleName(exceptionType);
                    //描述
                    cardInfo.setDescription("考勤机同步");
                    if (!StringUtils.isEmpty(personNumber)) {
                        //shr系统存在的人员才添加;
                        if (!persNoSet.contains(personNumber)) {
                            logger.error("打卡同步:personNumber not exist in shr system, personNumber=" + personNumber);
                            System.out.print("打卡同步:personNumber not exist in shr system, personNumber=" + personNumber);
                            continue;
                        }
                        // 姓名
                        PersonInfo personInfo = persInfoMap.get(personNumber);
                        cardInfo.setProposer(personInfo);
                        setCardId.add(personInfo.getId().toString());
                        cardColl.add(cardInfo);
                    }
                }
            }
            syncAttendanceRecords(setCardId, cardColl, ctx);
        } catch (Exception e) {
            logger.error("保存门禁打卡记录失败: " + e.getMessage(), e);
        }
        // 考勤档案

    }





    private void syncAttendanceRecords(Set<String> setCardId, CoreBaseCollection  cardColl, Context ctx) throws BOSException, EASBizException {
        // 获取考勤档案
        Map<String, AttendanceFileInfo> attendanceFileMap = new HashMap();
        StringBuffer oqlb = new StringBuffer();
        oqlb.append("select  proposer.number  , id ,attendanceNum,proposer.id,adminOrgUnit.id,adminOrgUnit.name,hrOrgUnit.id,hrOrgUnit.name,attAdminOrgUnit.id,attAdminOrgUnit.name  where proposer.id  in ( ");
        oqlb.append(AtsUtil.convertSetToString(setCardId));
        oqlb.append(")");
        AttendanceFileCollection coll = AttendanceFileFactory.getLocalInstance(ctx) .getAttendanceFileCollection(oqlb.toString());
        for (int i = 0; i < coll.size(); ++i) {
            PersonInfo proposer = coll.get(i).getProposer();
            if(null != proposer ) {
                attendanceFileMap.put(proposer.getId().toString(), coll.get(i));
            }
        }
//      Map<String, AttendanceFileInfo> attendanceFileMap = AttendanceFileFactory.getLocalInstance(ctx).getPersonByAttendanceNum(setCardId);
        logger.error("attendanceFileMap-----" + attendanceFileMap);
        logger.error("setCardId-----" + setCardId);
        IPerson personIns = PersonFactory.getLocalInstance(ctx);
        CoreBaseCollection cardCollFinally = new CoreBaseCollection();
        Collection<Map> seccussArray = new ArrayList<>();
        Collection<JSONObject> notExistRecords = new ArrayList<>();
        int success = 0;

        for (int i = 0; i < cardColl.size(); ++i) {
            Map<String, String> map = new HashMap<>();
            // 原始打卡记录实体
            PunchCardRecordInfo cardInfo = (PunchCardRecordInfo) cardColl.get(i);
            JSONObject jsObject = new JSONObject();
            jsObject.put("deviceid", cardInfo.getEquipmentNum()); // deviceid --EquNo
            jsObject.put("userid", cardInfo.getAttendanceNum()); // userid --CardId
            jsObject.put("RecDate", HRTimeWebUtils.dateShortToString(cardInfo.getPunchCardDate())); //checkin_time --RecDate
            jsObject.put("RecTime", HRTimeWebUtils.timestampToString(cardInfo.getPunchCardTime()).substring(11)); //checkin_time --RecTime
            map.put("userid", cardInfo.getAttendanceNum());
            map.put("RecDate", HRTimeWebUtils.dateShortToString(cardInfo.getPunchCardDate()));
            map.put("RecTime", HRTimeWebUtils.timestampToString(cardInfo.getPunchCardTime()).substring(11));

            // 员工是否有考勤档案
            if (attendanceFileMap.containsKey(cardInfo.getProposer().getId().toString())) {
                ++success;
                // 打卡位置 ，考勤机 的地址
                cardInfo.setPunchCardPlace(cardInfo.getPunchCardPlace());
                // 打卡来源
                cardInfo.setPunchCardSource(PunchCardSourceEnum.attenceMachine);
                // 考勤实体
                AttendanceFileInfo attendanceFileInfo = attendanceFileMap.get(cardInfo.getProposer().getId().toString());
                // HR 组织
                cardInfo.setHrOrgUnit(attendanceFileInfo.getHrOrgUnit());
                cardInfo.setAttendanceNum(attendanceFileInfo.getAttendanceNum());
                // 行政组织
                cardInfo.setAdminOrgUnit(attendanceFileInfo.getAdminOrgUnit());
                cardInfo.setCreator((UserInfo) ctx.get("UserInfo"));
                cardInfo.setLastUpdateUser((UserInfo) ctx.get("UserInfo"));
                cardInfo.setCreateTime(new Timestamp(new Date().getTime()));
                cardInfo.setLastUpdateTime(new Timestamp(new Date().getTime()));
                cardCollFinally.add(cardInfo);
                seccussArray.add(map);
            } else {
                notExistRecords.add(jsObject);
            }
        }

        logger.error("打卡同步保存到hr数量-----" + cardCollFinally.size());
        logger.error("打卡同步符合条件的写入数量-----" + success);
        logger.error("打卡同步时不存在考勤档案---" + notExistRecords);
        System.out.print("打卡同步时不存在考勤档案---" + notExistRecords);
        logger.error("打卡同步时不存在考勤档案数量-----" + notExistRecords.size());
        logger.error("seccussArray--Size-----" + seccussArray.size());
//        logger.error("seccussArray-----" + seccussArray);
        if (cardCollFinally.size() > 0) {
            // 分批大小
            int batchSize = 500;
            // 总记录数
            int totalRecords = cardCollFinally.size();
            // 计算需要分多少批
            int batchCount = (totalRecords + batchSize - 1) / batchSize;  // 向上取整
            logger.error("开始分批保存打卡数据，总记录数: " + totalRecords + "，将分" + batchCount + "批执行");
            // 分批处理
            for (int i = 0; i < batchCount; i++) {
                int fromIndex = i * batchSize;
                int toIndex = Math.min((i + 1) * batchSize, totalRecords);

                // 获取当前批次的数据
                CoreBaseCollection batch = new CoreBaseCollection();
                for (int j = fromIndex; j < toIndex; j++) {
                    batch.add(cardCollFinally.get(j));
                }

                // 执行批量保存
                IObjectPK[] iObjectPKS = PunchCardRecordFactory.getLocalInstance(ctx).saveBatchData(batch);
                logger.error("第" + (i + 1) + "批保存完成，记录数: " + iObjectPKS.length +
                        "，范围: " + fromIndex + "-" + (toIndex - 1));
            }
            logger.error("打卡数据分批保存完成，共处理" + totalRecords + "条记录");
        }

    }










    private HashSet<String>  getExistedPunchCardRecordCol(Context ctx, HashSet<String> attId) throws BOSException {
        HashSet<String> hashSet = new HashSet<String>();
        EntityViewInfo evi = new EntityViewInfo();
        FilterInfo fi = new FilterInfo();
        evi.setFilter(fi);
        evi.getSelector().add(new SelectorItemInfo("number"));
        fi.getFilterItems().add(new FilterItemInfo("number", attId, CompareType.INCLUDE));
        PunchCardRecordCollection existColl = PunchCardRecordFactory.getLocalInstance(ctx).getPunchCardRecordCollection(evi);
        for(int i =0 ;i<existColl.size();i++) {
            PunchCardRecordInfo punchCardRecordInfo = existColl.get(i);
            hashSet.add(punchCardRecordInfo.getNumber());
        }
        return hashSet;

    }




}