package com.cool.modules.dingtalk.service.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.cool.modules.dingtalk.entity.*;
import com.cool.modules.dingtalk.mapper.*;
import com.cool.modules.dingtalk.service.DingtalkConfigService;
import com.cool.modules.dingtalk.service.DingtalkSyncService;
import com.cool.modules.dingtalk.util.DingtalkApiUtil;
import com.cool.modules.user.entity.UserInfoEntity;
import com.cool.modules.user.mapper.UserInfoMapper;
import com.mybatisflex.core.query.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 钉钉同步服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DingtalkSyncServiceImpl implements DingtalkSyncService {

    private final DingtalkConfigService dingtalkConfigService;
    private final DingtalkApiUtil dingtalkApiUtil;
    private final DingtalkDepartmentMapper departmentMapper;
    private final DingtalkSyncLogMapper syncLogMapper;
    private final UserInfoMapper userInfoMapper;

    @Override
    @Async
    public void syncAll(Integer syncType) {
        log.info("【钉钉同步】开始执行完整同步, 同步类型: {}", syncType == 0 ? "手动" : "自动");

        long startTime = System.currentTimeMillis();

        // 创建同步日志
        DingtalkSyncLogEntity syncLog = new DingtalkSyncLogEntity();
        syncLog.setSyncType(syncType);
        syncLog.setSyncStatus(0); // 初始状态：失败
        syncLog.setDeptSuccessCount(0);
        syncLog.setDeptFailCount(0);
        syncLog.setUserSuccessCount(0);
        syncLog.setUserFailCount(0);

        try {
            // 检查配置
            DingtalkConfigEntity config = dingtalkConfigService.getConfig();
            if (config == null) {
                throw new RuntimeException("钉钉配置未完成");
            }

            // 检查同步状态
            if (config.getSyncStatus() == 1) {
                log.warn("【钉钉同步】同步任务正在执行中，拒绝新任务");
                throw new RuntimeException("同步任务正在执行中，请稍后再试");
            }

            // 更新同步状态为"同步中"
            config.setSyncStatus(1);
            dingtalkConfigService.updateById(config);

            // 初始化API工具
            dingtalkApiUtil.setConfig(config.getAppKey(), config.getAppSecret());

            // 同步部门
            int[] deptResult = syncDepartments();
            syncLog.setDeptSuccessCount(deptResult[0]);
            syncLog.setDeptFailCount(deptResult[1]);

            // 同步用户
            int[] userResult = syncUsers();
            syncLog.setUserSuccessCount(userResult[0]);
            syncLog.setUserFailCount(userResult[1]);

            // 判断同步状态
            if (syncLog.getDeptFailCount() == 0 && syncLog.getUserFailCount() == 0) {
                syncLog.setSyncStatus(1); // 完全成功
                log.info("【钉钉同步】同步完全成功");
            } else if (syncLog.getDeptSuccessCount() > 0 || syncLog.getUserSuccessCount() > 0) {
                syncLog.setSyncStatus(2); // 部分成功
                log.warn("【钉钉同步】同步部分成功");
            } else {
                syncLog.setSyncStatus(0); // 失败
                log.error("【钉钉同步】同步失败");
            }

        } catch (Exception e) {
            log.error("【钉钉同步】同步过程异常", e);
            syncLog.setSyncStatus(0);
            syncLog.setErrorMsg(e.getMessage());
        } finally {
            // 计算耗时
            long costTime = System.currentTimeMillis() - startTime;
            syncLog.setCostTime((int) costTime);

            // 保存同步日志
            syncLogMapper.insert(syncLog);
            log.info("【钉钉同步】同步完成, 耗时: {}ms, 日志ID: {}", costTime, syncLog.getId());

            // 重置同步状态
            DingtalkConfigEntity config = dingtalkConfigService.getConfig();
            if (config != null) {
                config.setSyncStatus(0);
                dingtalkConfigService.updateById(config);
            }
        }
    }

    /**
     * 同步部门信息
     *
     * @return [成功数量, 失败数量]
     */
    @Transactional
    public int[] syncDepartments() {
        log.info("【钉钉同步】开始同步部门");

        int successCount = 0;
        int failCount = 0;

        try {
            // 获取所有部门（递归）
            List<DingtalkDepartmentEntity> allDepts = new ArrayList<>();
            getAllDepartments(1L, allDepts); // 从根部门开始

            log.info("【钉钉同步】获取到 {} 个部门", allDepts.size());

            // 删除本地所有部门（全量同步）
            // 添加 where id >= 0 条件以满足 MyBatis-Flex 的安全限制
            QueryWrapper deleteQw = QueryWrapper.create()
                    .where(DingtalkDepartmentEntity::getId).ge(0);
            int deletedCount = departmentMapper.deleteByQuery(deleteQw);
            log.info("【钉钉同步】删除旧部门数据 {} 条", deletedCount);

            // 批量插入新部门
            for (DingtalkDepartmentEntity dept : allDepts) {
                try {
                    departmentMapper.insert(dept);
                    successCount++;
                } catch (Exception e) {
                    log.error("【钉钉同步】插入部门失败: {}", dept.getName(), e);
                    failCount++;
                }
            }

            log.info("【钉钉同步】部门同步完成, 成功: {}, 失败: {}", successCount, failCount);

        } catch (Exception e) {
            log.error("【钉钉同步】部门同步异常", e);
            failCount++;
        }

        return new int[]{successCount, failCount};
    }

    /**
     * 递归获取所有部门
     */
    private void getAllDepartments(Long parentId, List<DingtalkDepartmentEntity> allDepts) {
        try {
            JSONObject response = dingtalkApiUtil.getDepartmentListSub(parentId);

            // 检查响应是否成功
            Integer errcode = response.getInt("errcode");
            if (errcode == null || errcode != 0) {
                String errmsg = response.getStr("errmsg", "未知错误");
                log.error("【钉钉同步】获取部门列表失败, errcode: {}, errmsg: {}", errcode, errmsg);
                return;
            }

            // 钉钉API返回的result直接就是部门数组
            JSONArray deptList = response.getJSONArray("result");
            if (deptList == null || deptList.isEmpty()) {
                log.info("【钉钉同步】部门ID {} 下无子部门", parentId);
                return;
            }

            log.info("【钉钉同步】部门ID {} 下有 {} 个子部门", parentId, deptList.size());

            for (Object obj : deptList) {
                JSONObject deptJson = (JSONObject) obj;

                DingtalkDepartmentEntity dept = new DingtalkDepartmentEntity();
                dept.setDeptId(deptJson.getLong("dept_id"));
                dept.setName(deptJson.getStr("name"));
                dept.setParentId(deptJson.getLong("parent_id", 0L));
                dept.setDeptOrder(deptJson.getInt("order", 0));
                dept.setCreateDeptGroup(deptJson.getBool("create_dept_group", false));
                dept.setAutoAddUser(deptJson.getBool("auto_add_user", false));

                allDepts.add(dept);
                log.info("【钉钉同步】添加部门: id={}, name={}", dept.getDeptId(), dept.getName());

                // 递归获取子部门
                getAllDepartments(dept.getDeptId(), allDepts);
            }

        } catch (Exception e) {
            log.error("【钉钉同步】获取部门列表异常, parentId: {}", parentId, e);
        }
    }

    /**
     * 同步用户信息
     *
     * @return [成功数量, 失败数量]
     */
    @Transactional
    public int[] syncUsers() {
        log.info("【钉钉同步】开始同步用户");

        int successCount = 0;
        int failCount = 0;

        try {
            // 获取所有部门
            List<DingtalkDepartmentEntity> depts = departmentMapper.selectAll();
            log.info("【钉钉同步】共 {} 个部门需要同步用户", depts.size());

            Set<String> syncedUserIds = new HashSet<>();

            // 遍历每个部门获取用户
            for (DingtalkDepartmentEntity dept : depts) {
                try {
                    List<String> userIds = getUserIdsByDept(dept.getDeptId());

                    for (String userId : userIds) {
                        if (syncedUserIds.contains(userId)) {
                            continue; // 跳过已同步的用户
                        }

                        try {
                            syncUserDetail(userId, dept.getDeptId());
                            syncedUserIds.add(userId);
                            successCount++;
                        } catch (Exception e) {
                            log.error("【钉钉同步】同步用户失败, userId: {}", userId, e);
                            failCount++;
                        }
                    }

                } catch (Exception e) {
                    log.error("【钉钉同步】获取部门用户失败, deptId: {}", dept.getDeptId(), e);
                }
            }

            // 删除钉钉中已不存在的用户
            deleteNonExistUsers(syncedUserIds);

            log.info("【钉钉同步】用户同步完成, 成功: {}, 失败: {}", successCount, failCount);

        } catch (Exception e) {
            log.error("【钉钉同步】用户同步异常", e);
            failCount++;
        }

        return new int[]{successCount, failCount};
    }

    /**
     * 获取部门下所有用户ID（支持分页）
     */
    private List<String> getUserIdsByDept(Long deptId) {
        List<String> userIds = new ArrayList<>();
        long cursor = 0;
        int size = 100;
        boolean hasMore = true;

        while (hasMore) {
            try {
                JSONObject response = dingtalkApiUtil.getUserList(deptId, cursor, size);

                // 检查响应是否成功
                Integer errcode = response.getInt("errcode");
                if (errcode == null || errcode != 0) {
                    String errmsg = response.getStr("errmsg", "未知错误");
                    log.error("【钉钉同步】获取部门用户列表失败, deptId: {}, errcode: {}, errmsg: {}", deptId, errcode, errmsg);
                    break;
                }

                JSONObject result = response.getJSONObject("result");
                if (result == null) {
                    log.warn("【钉钉同步】部门用户列表结果为空, deptId: {}", deptId);
                    break;
                }

                JSONArray userList = result.getJSONArray("list");
                if (userList != null && !userList.isEmpty()) {
                    for (Object obj : userList) {
                        JSONObject userJson = (JSONObject) obj;
                        userIds.add(userJson.getStr("userid"));
                    }
                    log.info("【钉钉同步】部门 {} 本页获取 {} 个用户", deptId, userList.size());
                }

                hasMore = result.getBool("has_more", false);
                cursor = result.getLong("next_cursor", 0L);

            } catch (Exception e) {
                log.error("【钉钉同步】获取部门用户列表异常, deptId: {}", deptId, e);
                break;
            }
        }

        log.info("【钉钉同步】部门 {} 共获取 {} 个用户", deptId, userIds.size());
        return userIds;
    }

    /**
     * 同步用户详情
     */
    private void syncUserDetail(String dingtalkUserId, Long deptId) {
        JSONObject response = dingtalkApiUtil.getUserDetail(dingtalkUserId);

        // 检查响应是否成功
        Integer errcode = response.getInt("errcode");
        if (errcode == null || errcode != 0) {
            String errmsg = response.getStr("errmsg", "未知错误");
            log.error("【钉钉同步】获取用户详情失败, userId: {}, errcode: {}, errmsg: {}", dingtalkUserId, errcode, errmsg);
            return;
        }

        JSONObject result = response.getJSONObject("result");
        if (result == null) {
            log.warn("【钉钉同步】用户详情为空, userId: {}", dingtalkUserId);
            return;
        }

        // 查询本地是否已存在该用户
        QueryWrapper qw = QueryWrapper.create()
                .eq(UserInfoEntity::getDingtalkUserId, dingtalkUserId);
        UserInfoEntity user = userInfoMapper.selectOneByQuery(qw);

        boolean isNew = (user == null);
        if (isNew) {
            user = new UserInfoEntity();
        }

        // 更新用户信息
        user.setDingtalkUserId(dingtalkUserId);
        user.setDingtalkDeptId(deptId);
        user.setNickName(result.getStr("name"));
        user.setPhone(result.getStr("mobile"));
        user.setJobNumber(result.getStr("job_number"));
        user.setPosition(result.getStr("title"));
        user.setAvatarUrl(result.getStr("avatar"));

        if (isNew) {
            userInfoMapper.insert(user);
            log.info("【钉钉同步】新增用户: {}", user.getNickName());
        } else {
            userInfoMapper.update(user);
            log.info("【钉钉同步】更新用户: {}", user.getNickName());
        }
    }

    /**
     * 删除钉钉中已不存在的用户
     */
    private void deleteNonExistUsers(Set<String> syncedUserIds) {
        QueryWrapper qw = QueryWrapper.create()
                .isNotNull(UserInfoEntity::getDingtalkUserId);
        List<UserInfoEntity> allUsers = userInfoMapper.selectListByQuery(qw);

        int deleteCount = 0;
        for (UserInfoEntity user : allUsers) {
            if (!syncedUserIds.contains(user.getDingtalkUserId())) {
                userInfoMapper.deleteById(user.getId());
                deleteCount++;
                log.info("【钉钉同步】删除用户: {}", user.getNickName());
            }
        }

        log.info("【钉钉同步】删除 {} 个不存在的用户", deleteCount);
    }

    @Override
    public JSONObject checkSyncStatus() {
        log.info("【钉钉同步】检查同步状态");

        JSONObject result = JSONUtil.createObj();

        // 获取配置信息
        DingtalkConfigEntity config = dingtalkConfigService.getConfig();
        if (config != null) {
            // 当前是否正在同步
            result.set("isSyncing", config.getSyncStatus() == 1);

            // 下次同步时间（如果启用了自动同步）
            if (config.getAutoSync() == 1 && config.getSyncCron() != null) {
                result.set("nextSyncTime", "根据Cron表达式: " + config.getSyncCron());
            } else {
                result.set("nextSyncTime", "未启用自动同步");
            }
        } else {
            result.set("isSyncing", false);
            result.set("nextSyncTime", "未配置");
        }

        // 获取最新的同步日志
        QueryWrapper qw = QueryWrapper.create()
                .orderBy(DingtalkSyncLogEntity::getCreateTime, false)
                .limit(1);
        DingtalkSyncLogEntity latestLog = syncLogMapper.selectOneByQuery(qw);

        if (latestLog != null) {
            // 上次同步时间
            result.set("lastSyncTime", latestLog.getCreateTime());

            // 最新同步日志详情
            JSONObject logDetail = JSONUtil.createObj();
            logDetail.set("id", latestLog.getId());
            logDetail.set("syncType", latestLog.getSyncType());
            logDetail.set("syncStatus", latestLog.getSyncStatus());
            logDetail.set("deptSuccessCount", latestLog.getDeptSuccessCount());
            logDetail.set("deptFailCount", latestLog.getDeptFailCount());
            logDetail.set("userSuccessCount", latestLog.getUserSuccessCount());
            logDetail.set("userFailCount", latestLog.getUserFailCount());
            logDetail.set("errorMsg", latestLog.getErrorMsg());
            logDetail.set("costTime", latestLog.getCostTime());
            logDetail.set("createTime", latestLog.getCreateTime());

            result.set("latestLog", logDetail);
        } else {
            result.set("lastSyncTime", "暂无同步记录");
            result.set("latestLog", null);
        }

        log.info("【钉钉同步】同步状态: {}", result);
        return result;
    }
}
