package cn.iocoder.yudao.module.system.service.worklog;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptRespVO;
import cn.iocoder.yudao.module.system.controller.admin.worklog.vo.loginstance.LogInstanceNextOrUpVO;
import cn.iocoder.yudao.module.system.controller.admin.worklog.vo.loginstance.LogInstancePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.worklog.vo.loginstance.LogInstanceRespVO;
import cn.iocoder.yudao.module.system.controller.admin.worklog.vo.loginstance.LogInstanceSaveReqVO;
import cn.iocoder.yudao.module.system.convert.worklog.LogInstanceConvert;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.worklog.LogFormDO;
import cn.iocoder.yudao.module.system.dal.dataobject.worklog.LogInstanceDO;
import cn.iocoder.yudao.module.system.dal.dataobject.worklog.LogRuleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.worklog.LogStatisticsDO;
import cn.iocoder.yudao.module.system.dal.mysql.worklog.LogInstanceMapper;
import cn.iocoder.yudao.module.system.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import cn.iocoder.yudao.module.system.service.worklog.dto.LogReadUserRespDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;

/**
 * 日志实例的拓展 Service 实现类
 *
 * @author 符溶馨
 */
@Service
@Validated
public class LogInstanceServiceImpl implements LogInstanceService {

    @Resource
    private LogInstanceMapper logInstanceMapper;

    @Resource
    private DeptService deptService;

    @Resource
    private LogUseService logUseService;

    @Resource
    private LogFormService logFormService;

    @Resource
    private LogRuleService logRuleService;

    @Resource
    private AdminUserService adminUserService;

    @Resource
    private LogReadService logReadService;

    @Resource
    @Lazy
    private LogStatisticsService logStatisticsService;


    @Override
    public Long createLogInstance(LogInstanceSaveReqVO createReqVO) {

        //校验当前日志类型的日志 是否已提交过
        validateLogInstanceByType(createReqVO);

        LogInstanceDO logInstance = BeanUtils.toBean(createReqVO, LogInstanceDO.class);
        //获取当前登录用户id
        Long userId = getLoginUserId();
        //获取日志类型
        LogFormDO logFormDo = logFormService.getForm(createReqVO.getFormId());

        Long count = logUseService.getCountByUser(logFormDo.getId(), userId);
        if (count == 0L) {
            throw exception(LOG_FORM_NOT_USE);
        }

        //获取部门信息
        AdminUserDO adminUserDO = adminUserService.getUser(userId);
        //获取规则信息
        LogRuleDO logRuleDO = logRuleService.getLogRule(logFormDo.getId());

        //设置发起人用户编号
        logInstance.setStartUserId(userId);
        //设置发起人部门编号
        logInstance.setDeptId(adminUserDO.getDeptId());
        //设置日志类型
        logInstance.setType(logRuleDO.getType());
        //设置日志名称
        logInstance.setName(adminUserDO.getNickname() + createReqVO.getTime() + "的" + logFormDo.getName());

        // 插入提交状态
        Date thisDate = new Date();
        if (logRuleDO.getType() == 1) {
            Date endTime = DateUtils.buildTimeYYYYMMddHHmm(createReqVO.getTime(), logRuleDO.getEndTime());
            logInstance.setStatus(thisDate.getTime() < endTime.getTime() ? 1 : 2);
        } else {
            Date beginTime = DateUtil.beginOfWeek(thisDate);
            Date endTime = DateUtils.buildWeekHHmmTime(logRuleDO.getEndTime());
            logInstance.setStatus(DateUtil.isIn(thisDate, beginTime, endTime) ? 1 : 2);
        }
        // 插入
        logInstanceMapper.insert(logInstance);

        logStatisticsService.saveOrUpdate(new LogStatisticsDO()
                .setFormId(logFormDo.getId())
                .setRuleId(logRuleDO.getId())
                .setUserId(userId)
                .setDeptId(adminUserDO.getDeptId())
                .setLogInstanceExtId(logInstance.getId())
                .setType(logRuleDO.getType())
                .setTime(createReqVO.getTime())
                .setStatus(logInstance.getStatus())
                .setCommitTimeRange(logStatisticsService.getCommitTimeRange(logRuleDO))
        );
        //创建日志时，查询可以查看发起人日志的用户组  用线程控制
        new Thread(() -> {

            List<LogReadUserRespDTO> respDTOS = logInstanceMapper.selectRaedUser(userId, adminUserDO.getDeptId());

            //特殊情况， 日志发起人为研发部时 手动添加查看者
            if (adminUserDO.getDeptId() == 128L && adminUserDO.getId() != 126L) {

                LogReadUserRespDTO dto = new LogReadUserRespDTO();
                dto.setUserId(126L);
                dto.setDeptId(128L);
                respDTOS.add(dto);
            }

            logReadService.createLogRule(respDTOS, logInstance.getId(), logInstance.getStartUserId());
        }).start();

        // 返回
        return logInstance.getId();
    }

    /**
     * 校验当前日志类型的日志 是否已提交过
     */
    private void validateLogInstanceByType(LogInstanceSaveReqVO createReqVO) {

        List<String> dateList = new ArrayList<>();
        if (createReqVO.getType() == 1) {

            dateList.add(createReqVO.getTime());
        } else {

            String[] times = createReqVO.getTime().split(",");
            dateList = DateUtils.betweenDayStrList(times[0], times[1]);

            createReqVO.setTime(times[1]);
        }

        Long count = logInstanceMapper.getLogByType(createReqVO.getType(), getLoginUserId(), dateList);
        if (count > 0L) {

            throw exception(ErrorCodeConstants.LOG_TYPE_EXISTS);
        }
    }

    @Override
    public void updateLogInstance(LogInstanceSaveReqVO updateReqVO) {
        // 校验存在
        validateLogInstanceExists(updateReqVO.getId());

        //校验要修改的日志是否是当天发送的
        LogInstanceDO logInstanceDO = logInstanceMapper.selectById(updateReqVO.getId());
        if (!logInstanceDO.getCreateTime().toLocalDate().equals(LocalDate.now())) {

            throw exception(LOG_NOT_DATE);
        }

        LogRuleDO logRuleDO = logRuleService.getLogRuleByFormId(updateReqVO.getFormId());
        String endTime = logRuleDO.getEndTime();
        if (logRuleDO.getType() != 1) {

            endTime = endTime.split(",")[1];
        }

        if (LocalTime.now().isAfter(LocalTime.parse(endTime))) {
            throw exception(LOG_NOT_UPDATE);
        }

        // 更新
        LogInstanceDO updateObj = BeanUtils.toBean(updateReqVO, LogInstanceDO.class);
        logInstanceMapper.updateById(updateObj);
    }

    @Override
    public void deleteLogInstance(Long id) {
        // 校验存在
        validateLogInstanceExists(id);
        // 删除
        logInstanceMapper.deleteById(id);
    }

    private void validateLogInstanceExists(Long id) {
        if (logInstanceMapper.selectById(id) == null) {
            throw exception(LOG_INSTANCE_NOT_EXISTS);
        }
    }

    @Override
    public LogInstanceRespVO getLogInstance(Long id) {

        //获取日志详情
        LogInstanceDO logInstanceDO = logInstanceMapper.selectById(id);
//        LogInstanceRespVO logInstanceRespVO = logInstanceMapper.selectPageResult(new LogInstancePageReqVO(), getLoginUserId(), null, id);

        //设置日志详情 模板内容和时间
        return setContentFun(LogInstanceConvert.INSTANCE.convert(logInstanceDO));
    }

    @Override
    public IPage<LogInstanceRespVO> getLogInstancePage(LogInstancePageReqVO pageReqVO, Integer pagingType) {

        List<Long> leaderUserIds = new ArrayList<>();

        //判断特殊情况， 只需查看各部门领导人得日志
        if (pageReqVO.getIsBoss() != null && pageReqVO.getIsBoss() == 1) {

            //查询两级以及三级部门得领导人
            //以及岗位为总监或副总监的用户
            leaderUserIds = adminUserService.getUserByBoss();
        }

        Page<LogInstanceRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        IPage<LogInstanceRespVO> pageList = logInstanceMapper.selectPageResult(page, pageReqVO, getLoginUserId(), pagingType, leaderUserIds);

        List<LogInstanceRespVO> records = pageList.getRecords();
        if (!records.isEmpty()) {

            //模版ids过滤
            List<Long> workFormIds = records.stream().map(LogInstanceRespVO::getFormId).collect(Collectors.toList());

            //  查询模版列表
            List<LogFormDO> formList = logFormService.getFormList(workFormIds);
            Map<Long, LogFormDO> formMap = formList.stream().collect(Collectors.toMap(LogFormDO::getId, item -> item));

            //查询用户信息列表
            List<Long> userIds = records.stream().map(LogInstanceRespVO::getStartUserId).collect(Collectors.toList());
            Map<Long, AdminUserDO> userMap = adminUserService.getUserMap(userIds);

            //遍历
            records.forEach(item -> {

                //设置发起人用户名称和头像
                AdminUserDO userDO = userMap.get(item.getStartUserId());
                item.setStartUserName(userDO.getNickname());
                item.setAvatar(userDO.getAvatar());

                //设置日志内部分
                LogFormDO logFormDO = formMap.get(item.getFormId());
                List<String> fields = logFormDO.getFields();
                StringBuilder workLogContent = new StringBuilder();
                if (!item.getFormVariables().isEmpty()) {
                    JSONObject workLogContentJson = new JSONObject(item.getFormVariables());
                    for (String fieldItem : fields) {
                        JSONObject fieldJson = new JSONObject(fieldItem);
                        String fieldStr = fieldJson.getStr("field");
                        String title = fieldJson.getStr("title");
                        String field = workLogContentJson.getStr(fieldStr);
                        workLogContent.append(title).append(":").append(field).append("  ");
                    }
                }
                item.setWorkLogContent(workLogContent.toString());

                //设置时间
                LocalDate nowDate = LocalDate.now();
                LocalDateTime createTime = LocalDateTime.parse(item.getCreateTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
                //日志创建时间是当前日期时
                if (createTime.toLocalDate().equals(nowDate)) {
                    item.setCreateTime("今日 " + createTime.toLocalTime().format(DateTimeFormatter.ofPattern("HH:mm")));
                }
                //日志创建时间是当前日期前一天时
                if (createTime.toLocalDate().equals(nowDate.minusDays(1))) {
                    item.setCreateTime("昨日 " + createTime.toLocalTime().format(DateTimeFormatter.ofPattern("HH:mm")));
                }
            });
        }

        return pageList;
    }

    @Override
    public List<DeptRespVO> getDeptInfo() {

        List<LogInstanceDO> logInstanceDOS = logInstanceMapper.selectList();
        List<Long> deptIds = logInstanceDOS.stream()
                .map(LogInstanceDO::getDeptId) // 获取每个LogInstanceDO的 deptId
                .collect(Collectors.toList()); // 收集成List

        List<DeptDO> deptDOS = deptService.getDeptList(deptIds);
        return BeanUtils.toBean(deptDOS, DeptRespVO.class);
    }

    @Override
    public LogInstanceDO getUpLog(Long formId) {

        List<LogInstanceDO> logInstanceDOS = logInstanceMapper.getUpLog(getLoginUserId(), formId);
        if (!logInstanceDOS.isEmpty()) {

            return logInstanceDOS.get(0);
        }

        return null;
    }

    @Override
    public LogInstanceRespVO setContentFun(LogInstanceRespVO logInstanceRespVO) {

        if (logInstanceRespVO == null) {
            return null;
        }
        //获取模板信息
        LogFormDO logFormDO = logFormService.getForm(logInstanceRespVO.getFormId());
        List<String> fields = logFormDO.getFields();
        List<Map<String, String>> logDetail = new ArrayList<>();

        if (!logInstanceRespVO.getFormVariables().isEmpty()) {
            JSONObject workLogContentJson = new JSONObject(logInstanceRespVO.getFormVariables());
            for (String fieldItem : fields) {
                Map<String, String> detail = new HashMap<>();

                JSONObject fieldJson = new JSONObject(fieldItem);
                String fieldStr = fieldJson.getStr("field");
                String title = fieldJson.getStr("title");
                String field = workLogContentJson.getStr(fieldStr);

                detail.put("title", title);
                detail.put("value", field);
                logDetail.add(detail);
            }
            logInstanceRespVO.setLogDetail(logDetail);
        }
        //设置时间
        LocalDate nowDate = LocalDate.now();
        LocalDateTime createTime = LocalDateTime.parse(logInstanceRespVO.getCreateTime(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        //日志创建时间是当前日期时
        if (createTime.toLocalDate().equals(nowDate)) {
            logInstanceRespVO.setCreateTime("今日 " + createTime.toLocalTime().format(DateTimeFormatter.ofPattern("HH:mm")));
        }
        //日志创建时间是当前日期前一天时
        if (createTime.toLocalDate().equals(nowDate.minusDays(1))) {
            logInstanceRespVO.setCreateTime("昨日 " + createTime.toLocalTime().format(DateTimeFormatter.ofPattern("HH:mm")));
        }

        return logInstanceRespVO;
    }

    @Override
    public LogInstanceNextOrUpVO getNextOrUp(LogInstancePageReqVO dto, Long id, Integer pagingType) {
        LogInstanceNextOrUpVO vo = new LogInstanceNextOrUpVO();
        List<Long> leaderUserIds = new ArrayList<>();
        //判断特殊情况， 只需查看各部门领导人得日志
        if (dto.getIsBoss() != null && dto.getIsBoss() == 1) {
            //查询两级以及三级部门得领导人
            //以及岗位为总监或副总监的用户
            leaderUserIds = adminUserService.getUserByBoss();
        }
        LogInstanceRespVO upLogInstance = logInstanceMapper.getNextOrUp(dto, id, getLoginUserId(), 1, pagingType, leaderUserIds);
        LogInstanceRespVO nextLogInstance = logInstanceMapper.getNextOrUp(dto, id, getLoginUserId(), 0, pagingType, leaderUserIds);
        vo.setUpLogInstance(upLogInstance);
        vo.setNextLogInstance(nextLogInstance);
        //获取日志详情
        return vo;
    }


    @Override
    public List<LogInstanceDO> getNeedWriteLogInstanceByTimeRange(Long fromId, List<String> time, Long userId) {
        return logInstanceMapper.selectList(new LambdaQueryWrapper<LogInstanceDO>()
                .eq(LogInstanceDO::getFormId, fromId)
                .in(LogInstanceDO::getTime, time)
                .eq(userId != null, LogInstanceDO::getStartUserId, userId));
    }
}