package com.czg.service.market.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.czg.market.vo.DingAttendanceStatsVO;
import com.czg.market.vo.DingUserVO;
import com.czg.service.RedisService;
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.taobao.api.ApiException;
import com.taobao.api.TaobaoResponse;
import com.taobao.api.internal.util.StringUtils;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

@Service
public class DingService {
    public static final Map<String, String> STATUS_MAP = new HashMap<>(){{
        put("Normal", "正常");
        put("Early", "早退");
        put("Late", "迟到");
        put("SeriousLate", "严重迟到");
        put("Absenteeism", "旷工迟到");
        put("NotSigned", "未打卡");
    }};

    @Resource
    private RedisService redisService;



    public String getToken(String key, String secret, Long shopId) {
        Object accessToken = redisService.get("ding_access_token:" + shopId);
        if (accessToken instanceof String && StrUtil.isNotBlank((String) accessToken)) {
            return (String) accessToken;
        }
        DingTalkClient client = new DefaultDingTalkClient("https://api.dingtalk.com/gettoken");
        OapiGettokenRequest req = new OapiGettokenRequest();
//        req.setAppkey("ding9bqzj4890z81o3y2");
//        req.setAppsecret("PiRU2CQ_KrZH104UoULeBfSbFw4YhPI0fZZC_bUr1aubvbsP6zmMv7nC1xxF9QBS");
        req.setAppkey(key);
        req.setAppsecret(secret);
        req.setHttpMethod("GET");
        OapiGettokenResponse rsp;
        try {
            rsp = client.execute(req);
        } catch (ApiException e) {
            throw new RuntimeException(e);
        }
        System.out.println(rsp.getBody());
        JSONObject data = getData(rsp, true);
        Long expiresIn = data.getLong("expires_in");
        redisService.set("ding_access_token:" + shopId, data.getString("access_token"), expiresIn - 100);
        return data.getString("access_token");
    }

    public String getColumIdByName(String key, String secret, Long shopId, String name) {
        Map<String, String> columns = getColumns(key, secret, shopId);
        String columId = null;
        for (Map.Entry<String, String> entry : columns.entrySet()) {
            String key1 = entry.getKey();
            String value = entry.getValue();
            if (value.equals(name)) {
                columId = key1;
                break;
            }
        }
        return columId;
    }

    public Map<String, String> getColumns(String key, String secret, Long shopId) {
        Object value = redisService.get("ding_columns:" + shopId);
        if (value instanceof String && StrUtil.isNotBlank((String) value)) {
            return JSONObject.parseObject((String) value, Map.class);
        }
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/attendance/getattcolumns");
        OapiAttendanceGetattcolumnsRequest req = new OapiAttendanceGetattcolumnsRequest();
        OapiAttendanceGetattcolumnsResponse rsp = null;
        try {
            String token = getToken(key, secret, shopId);
            rsp = client.execute(req, token);
        } catch (ApiException e) {
            throw new RuntimeException(e);
        }

        JSONObject jsonObject = JSONObject.parseObject(rsp.getBody());
        if (jsonObject.getInteger("errcode") != 0) {
            throw new RuntimeException(jsonObject.getString("errmsg"));
        }
        HashMap<String, String> map = new HashMap<>();
        Map<String, String> columMap = jsonObject.getJSONObject("result").getJSONArray("columns").stream()
                .filter(item -> {
                    JSONObject item1 = (JSONObject) item;
                    return item1.containsKey("id") && CollUtil.newArrayList("出勤天数", "休息天数", "工作时长", "迟到次数", "迟到时长", "应出勤天数", "旷工迟到次数").contains(item1.getString("name"));
                })
                .collect(Collectors.toMap(item -> ((JSONObject) item).getLong("id").toString(), item -> ((JSONObject) item).getString("name")));

        redisService.set("ding_columns:" + shopId, JSONObject.toJSONString(columMap));
        return columMap;
    }

    public static JSONObject getData(TaobaoResponse response, boolean checkNull) {
        if (!"0".equals(response.getErrorCode())) {
            Map<String, Object> map = BeanUtil.beanToMap(response);
            throw new RuntimeException(map.get("errmsg").toString());
        }
        String body = response.getBody();
        if (body == null) {
            if (checkNull) {
                throw new RuntimeException("body is null");
            }
            return null;
        }
        JSONObject jsonObject = JSONObject.parseObject(body);
        if (jsonObject.getInteger("errcode") != 0) {
            throw new RuntimeException(jsonObject.getString("errmsg"));
        }
        return jsonObject;
    }

    public List<DingUserVO> getUserByDeptId(Long deptId, String key, String secret, Long shopId) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/list");
        OapiV2UserListRequest req = new OapiV2UserListRequest();
        req.setDeptId(deptId);
        req.setCursor(0L);
        req.setSize(50L);
        req.setOrderField("modify_desc");
        req.setContainAccessLimit(true);
        req.setLanguage("zh_CN");
        OapiV2UserListResponse rsp = client.execute(req, getToken(key, secret, shopId));
        JSONObject data = getData(rsp, true);
        List<DingUserVO> userVOList = data.getJSONObject("result").getJSONArray("list").toJavaList(DingUserVO.class);
        return userVOList;
    }

    public JSONObject getRepost(Date startTime, Date endTime, String userId, String columIdList, String key, String secret, Long shopId) throws ApiException {
        DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/attendance/getcolumnval");
        OapiAttendanceGetcolumnvalRequest req = new OapiAttendanceGetcolumnvalRequest();
        req.setUserid(userId);
        req.setColumnIdList(columIdList);
        req.setFromDate(startTime);
        req.setToDate(endTime);
        OapiAttendanceGetcolumnvalResponse rsp = client.execute(req, getToken(key, secret, shopId));
        JSONObject data = getData(rsp, false);
        return data == null ? null : data.getJSONObject("result");
    }

    public String getAttendanceStatus(String key, String secret, Long shopId, Date date, String userId) {
        String status = "";
        try {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/attendance/getupdatedata");
            OapiAttendanceGetupdatedataRequest req = new OapiAttendanceGetupdatedataRequest();
            req.setUserid(userId);
            req.setWorkDate(date);
            OapiAttendanceGetupdatedataResponse rsp = client.execute(req, getToken(key, secret, shopId));
            System.out.println(rsp.getBody());
            JSONArray resultList = JSONObject.parseObject(rsp.getBody()).getJSONObject("result").getJSONArray("attendance_result_list");

            if (resultList.isEmpty()) {
                if (DateUtil.date(date).toLocalDateTime().toLocalDate().compareTo(DateUtil.date().toLocalDateTime().toLocalDate()) == 0) {
                    status = "未打卡";
                }else {
                    status = "休息日";
                }
            }
            int notSignedCount = 0;

            for (int i = 0, resultListSize = resultList.size(); i < resultListSize; i++) {
                Object item = resultList.get(i);

                JSONObject jsonObject = (JSONObject) item;
                String timeResult = jsonObject.getString("time_result");
                String checkType = jsonObject.getString("check_type");

                if ("NotSigned".equals(timeResult)) {
                    notSignedCount++;
                }

                if (notSignedCount >= 2) {
                    status = "旷工";
                    break;
                }

                if (i > 1 && !"正常".equals(status)) {
                    break;
                }

                status = STATUS_MAP.get(timeResult);
                if (!"正常".equals(status)) {
                    status = ("OnDuty".equals(checkType) ? "上班" : "下班") + status;
                }
            }

            return status;
        } catch (ApiException e) {
            throw new RuntimeException(e);
        }
    }

    public ArrayList<DingUserVO> getUserList(String name, String key, String secret, Long shopId, String userId) {
        try {
            DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
            OapiV2DepartmentListsubRequest req = new OapiV2DepartmentListsubRequest();
            req.setDeptId(1L);
            req.setLanguage("zh_CN");

            OapiV2DepartmentListsubResponse rsp = client.execute(req, getToken(key, secret, shopId));

            Set<Long> deptIdList = getData(rsp, true).getJSONArray("result")
                    .stream()
                    .map(item -> ((JSONObject) item).getLong("dept_id"))
                    .collect(Collectors.toSet());

            // 线程池：按 CPU 核数 * 2
            ExecutorService pool = Executors.newFixedThreadPool(
                    Math.min(deptIdList.size(), Runtime.getRuntime().availableProcessors() * 2)
            );

            List<Future<List<DingUserVO>>> futures = new ArrayList<>();

            // 并发拉取
            for (Long deptId : deptIdList) {
                futures.add(pool.submit(() -> getUserByDeptId(deptId, key, secret, shopId)));
            }

            // 汇总结果
            List<DingUserVO> allUsers = new ArrayList<>();
            for (Future<List<DingUserVO>> f : futures) {
                allUsers.addAll(f.get());
            }

            pool.shutdown();

            // 正确过滤逻辑
            return allUsers.stream().filter(item -> {
                if (StrUtil.isNotBlank(userId) && !item.getUserid().equals(userId)) {
                    return false;
                }
                return !StrUtil.isNotBlank(name) || item.getName().contains(name);
            }).collect(Collectors.toCollection(ArrayList::new));

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    public ArrayList<DingAttendanceStatsVO> getUserReport(Long shopId, String key, String secret, DateTime startTime, DateTime endTime, String name, String userId) {
        Map<String, String> columns = getColumns(key, secret, shopId);
        ArrayList<DingUserVO> userList = getUserList(name, key, secret, shopId, userId);
        ArrayList<DingAttendanceStatsVO> statsVOS = new ArrayList<>();
        for (DingUserVO item : userList) {
            JSONObject repost = null;
            try {
                repost = getRepost(startTime, endTime, item.getUserid(),
                        String.join(",", columns.keySet()), key, secret, shopId);
            } catch (ApiException e) {
                throw new RuntimeException(e);
            }
            DingAttendanceStatsVO statsVO = new DingAttendanceStatsVO();
            statsVOS.add(statsVO);
            statsVO.setUserId(item.getUserid());
            statsVO.setName(item.getName());
            if (repost != null) {
                statsVO.setActive(true);
//                statsVO.setReport(repost.getJSONArray("column_vals"));
                repost.getJSONArray("column_vals").forEach(info -> {
                    JSONObject infoObj = (JSONObject) info;
                    Long id = infoObj.getJSONObject("column_vo").getLong("id");


                    BigDecimal value = BigDecimal.ZERO;
                    for (Object column : infoObj.getJSONArray("column_vals")) {
                        JSONObject columnObj = (JSONObject) column;
                        value = value.add(new BigDecimal(columnObj.getString("value")));
                    }
                    statsVO.setValByName(columns.get(id.toString()), value.stripTrailingZeros().toPlainString());
                });
            }
        }

        return statsVOS;
    }

    static void main() throws ApiException {
    }
}
