package jnpf.culture.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import jnpf.base.service.SuperServiceImpl;
import jnpf.culture.mapper.CulturePicTempMapper;
import jnpf.culture.mapper.CultureTextSettingMapper;
import jnpf.culture.service.CultureTextSettingService;
import jnpf.entity.culture.CulturePicTemp;
import jnpf.entity.culture.CultureTextSetting;
import jnpf.enums.attendance.StatisticsEnumUtil;
import jnpf.exception.HandleException;
import jnpf.model.culture.dto.CultureTextSettingDto;
import jnpf.model.culture.dto.SettingQueryDto;
import jnpf.model.culture.vo.CultureStatVo;
import jnpf.model.culture.vo.CultureTextSettingVo;
import jnpf.model.culture.vo.UploadInfoVo;
import jnpf.model.personnels.dto.staff.roster.FtbPersonnelsStaffRosterDto;
import jnpf.model.personnels.req.roster.StaffRosterReq;
import jnpf.personnels.service.FtbPersonnelsStaffRosterService;
import jnpf.util.*;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 文化打卡 - 文字配置 服务实现
 *
 * @author yanwenfu
 * @create 2025-12-23
 */
@Service
public class CultureTextSettingServiceImpl extends SuperServiceImpl<CultureTextSettingMapper, CultureTextSetting> implements CultureTextSettingService {

    @Resource
    private CultureTextSettingMapper cultureTextSettingMapper;
    @Resource
    private CulturePicTempMapper culturePicTempMapper;
    @Resource
    private FtbPersonnelsStaffRosterService staffRosterService;

    private static final Pattern EMOJI_PATTERN = Pattern.compile(
            "[\uD83C\uDF00-\uD83D\uDDFF]|" +
                    "[\uD83D\uDE00-\uD83D\uDE4F]|" +
                    "[\uD83D\uDE80-\uD83D\uDEFF]|" +
                    "[\u2600-\u26FF]|" +
                    "[\u2700-\u27BF]",
            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE
    );

    @Override
    public PageInfo<CultureTextSettingVo> getCultureTextSettingList(SettingQueryDto queryDto) {

        PageHelper.startPage(queryDto.getCurrentPage(), queryDto.getPageSize());
        PageInfo<CultureTextSettingVo> page = new PageInfo<>(cultureTextSettingMapper.getCultureTextSettingList(queryDto.getKeyword()));
        if (page.getList().isEmpty()) {
            page.setPageSize(queryDto.getPageSize());
            page.setPageNum(queryDto.getCurrentPage());
            return page;
        }
        // 设置人员信息
        List<String> userIds = page.getList().stream().map(CultureTextSettingVo::getLastModifyUserId).distinct().collect(Collectors.toList());
        StaffRosterReq req = new StaffRosterReq();
        req.setUserIds(userIds);
        List<FtbPersonnelsStaffRosterDto> data = staffRosterService.queryWithUserIdsPost(req);
        if (null != data && !data.isEmpty()) {
            Map<String, FtbPersonnelsStaffRosterDto> userMap = data.stream().collect(Collectors.toMap(FtbPersonnelsStaffRosterDto::getUserId, Function.identity()));
            page.getList().forEach(v -> {
                FtbPersonnelsStaffRosterDto user = userMap.get(v.getLastModifyUserId());
                if (null != user) {
                    v.setLastModifyUserName(user.getName());
                    if (user.getEnabledMark() == ConstantUtil.NUM_TRUE) {
                        v.setLastModifyUserName(v.getLastModifyUserName() + "（已删除）");
                    } else {
                        if (user.getWorkerStatus().equals(StatisticsEnumUtil.WorkStatusEnum.LZ.getCode())) {
                            v.setLastModifyUserName(v.getLastModifyUserName() + "（已离职）");
                        }
                    }
                }
            });
        }
        return page;
    }

    @Override
    public void addTextSetting(CultureTextSettingDto textSettingDto) throws Exception {

        // 判定是否超过最大配置数量 100
        LambdaQueryWrapper<CultureTextSetting> queryWrapper = new LambdaQueryWrapper<CultureTextSetting>()
                .eq(CultureTextSetting::getDeleteMark, ConstantUtil.NUM_FALSE);
        Long total = cultureTextSettingMapper.selectCount(queryWrapper);
        if (total.intValue() >= 100) {
            throw new HandleException("您已超过最大配置数量");
        }
        // 查询文案是否已经存在 判定方式为 标题 + 文字 是否重复
        int count = cultureTextSettingMapper.getDistinctCount(textSettingDto.getCultureTitle(), textSettingDto.getCultureContent(), null);
        if (count > 0) {
            throw new HandleException("新增内容已存在，无法重复添加");
        }
        CultureTextSetting setting = new CultureTextSetting();
        setting.setId(FtbUtil.getId());
        setting.setCultureTitle(textSettingDto.getCultureTitle());
        setting.setCultureContent(textSettingDto.getCultureContent());
        setting.setDeleteMark(ConstantUtil.NUM_FALSE);
        setting.setCreatorUserId(UserProvider.getLoginUserId());
        setting.setLastModifyUserId(UserProvider.getLoginUserId());
        cultureTextSettingMapper.insert(setting);
    }

    @Override
    public void updateTextSetting(String id, CultureTextSettingDto textSettingDto) throws Exception {

        CultureTextSetting setting = cultureTextSettingMapper.selectById(id);
        if (null == setting) {
            throw new HandleException("未找到配置");
        }
        int count = cultureTextSettingMapper.getDistinctCount(textSettingDto.getCultureTitle(), textSettingDto.getCultureContent(), id);
        if (count > 0) {
            throw new HandleException("内容已存在，无法重复添加");
        }
        setting.setCultureTitle(textSettingDto.getCultureTitle());
        setting.setCultureContent(textSettingDto.getCultureContent());
        setting.setLastModifyUserId(UserProvider.getLoginUserId());
        setting.setLastModifyTime(new Date());
        cultureTextSettingMapper.updateById(setting);
        // 删除文字配置关联的临时图片
        LambdaQueryWrapper<CulturePicTemp> queryWrapper = new LambdaQueryWrapper<CulturePicTemp>()
                .in(CulturePicTemp::getContentId, id);
        culturePicTempMapper.delete(queryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteTextSettingBatch(List<String> ids) throws Exception {

        Long dbCount = getDbCount();
        if (dbCount.intValue() - ids.size() < 1) {
            throw new HandleException("至少需保留一条文化内容，不可全部删除");
        }
        // 删除文字配置
        LambdaUpdateWrapper<CultureTextSetting> updateWrapper = new LambdaUpdateWrapper<CultureTextSetting>()
                .in(CultureTextSetting::getId, ids)
                .set(CultureTextSetting::getDeleteMark, ConstantUtil.NUM_TRUE)
                .set(CultureTextSetting::getDeleteUserId, UserProvider.getLoginUserId())
                .set(CultureTextSetting::getDeleteTime, new Date());
        cultureTextSettingMapper.update(null, updateWrapper);
        // 删除文字配置关联的临时图片
        LambdaQueryWrapper<CulturePicTemp> queryWrapper = new LambdaQueryWrapper<CulturePicTemp>()
                .in(CulturePicTemp::getContentId, ids);
        culturePicTempMapper.delete(queryWrapper);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public UploadInfoVo textSettingImport(MultipartFile file) throws Exception {

        UploadInfoVo uploadInfo = new UploadInfoVo();
        XSSFWorkbook workbook;
        try {
            workbook = new XSSFWorkbook(file.getInputStream());
        } catch (Exception e) {
            throw new HandleException("导入转换工作簿异常");
        }
        // 获取数据
        XSSFSheet sheet = workbook.getSheetAt(0);
        List<String[]> dataFromSheet = TemplateExcelUtils.getDataFromSheetWithNullRow(sheet);
        if (dataFromSheet.isEmpty() || dataFromSheet.size() == 1) {
            throw new HandleException("未获取到工作簿数据");
        }
        List<CultureTextSetting> list = new ArrayList<>();
        Set<String> set = new HashSet<>();
        String[] row1 = dataFromSheet.get(0);
        if (row1.length < 2 || !row1[0].equals("文化标题") || !row1[1].equals("文化内容")) {
            throw new HandleException("当前模板非文化内容模板，请上传正确模板及内容");
        }
        LocalDateTime now = LocalDateTime.now();
        for (int i = 1; i < dataFromSheet.size(); i++) {
            List<String> array = List.of(dataFromSheet.get(i));
            if (StringUtil.isEmpty(array.get(0)) && StringUtil.isEmpty(array.get(1))) {
                continue;
            }
            CultureTextSetting setting = new CultureTextSetting();
            setting.setId(FtbUtil.getId());
            String titleAndContent = "";
            String errorMsg = "";
            for (int j = 0; j < array.size(); j++) {
                String str = array.get(j);
                if (j == 0) {
                    // 标题
                    titleAndContent += str;
                    String msg = checkStr(i, j, str, 50, errorMsg);
                    if (StringUtil.isNotEmpty(msg)) {
                        errorMsg += msg;
                    }
                }
                if (j == 1) {
                    // 内容
                    titleAndContent += "\u0001" + str;
                    String msg = checkStr(i, j, str, 200, errorMsg);
                    if (StringUtil.isNotEmpty(msg)) {
                        errorMsg += StringUtil.isNotEmpty(errorMsg) ? "，" + msg : msg;
                    }
                }
            }
            // 报错了
            if (StringUtil.isNotEmpty(errorMsg)) {
                uploadInfo.getFailMsgList().add(errorMsg);
                uploadInfo.setFailNum(uploadInfo.getFailNum() + 1);
                continue;
            }
            if (StringUtil.isEmpty(titleAndContent)) {
                continue;
            }
            // 说明内容未重复
            if (set.add(titleAndContent)) {
                String[] split = titleAndContent.split("\u0001");
                setting.setIndex(i);
                setting.setCultureTitle(split[0]);
                setting.setCultureContent(split[1]);
                setting.setDeleteMark(ConstantUtil.NUM_FALSE);
                setting.setCreatorUserId(UserProvider.getLoginUserId());
                now = now.plusSeconds(1);
                setting.setCreatorTime(Date.from(now.atZone(ZoneId.systemDefault()).toInstant()));
                setting.setLastModifyUserId(UserProvider.getLoginUserId());
                setting.setLastModifyTime(setting.getCreatorTime());
                list.add(setting);
            } else {
                uploadInfo.getFailMsgList().add("第" + (i + 1) + "行 文化标题文本信息已存在");
                uploadInfo.setFailNum(uploadInfo.getFailNum() + 1);
            }
        }
        if (!list.isEmpty()) {
            // 判断list size + db size是否大于100 舍弃大于100的
            Long dbCount = getDbCount();
            // 还能导入的条数
            int insertCount = 100 - dbCount.intValue();
            if (insertCount <= 0) {
                // 数据库配置数已满, 无法导入
                // -1 是因为第一条是表头
                uploadInfo.setFailNum(uploadInfo.getFailNum() + list.size());
                uploadInfo.getFailMsgList().add("无可导入的内容，已超过文字配置最大条数（100）限制");
                return uploadInfo;
            }
            // 判断list中有没有与数据库重复的
            List<Integer> exceptIndex = cultureTextSettingMapper.getDistinctCountBatch(list);
            // 去除重复的
            if (!exceptIndex.isEmpty()) {
                list.removeIf(v -> exceptIndex.contains(v.getIndex()));
                uploadInfo.getFailMsgList().add("第" + exceptIndex.stream().sorted().map(v -> String.valueOf(v + 1)).collect(Collectors.joining("，")) + "行 无法导入，文化内容已存在");
                uploadInfo.setFailNum(uploadInfo.getFailNum() + exceptIndex.size());
            }
            // 不可导入的条数
            int overflowCount = insertCount - list.size();
            if (overflowCount < 0) {
                overflowCount = Math.abs(overflowCount);
                uploadInfo.setFailNum(uploadInfo.getFailNum() + overflowCount);
                // 被截掉的部分，取最后 exceptCount 条
                List<Integer> removedIndexes = list.subList(list.size() - overflowCount, list.size())
                        .stream()
                        .map(CultureTextSetting::getIndex)
                        .collect(Collectors.toList());
                list = new ArrayList<>(list.subList(0, list.size() - overflowCount));
                uploadInfo.getFailMsgList().add("第" + removedIndexes.stream().sorted().map(v -> String.valueOf(v + 1)).collect(Collectors.joining("，")) + "行无法导入，已超过文字配置最大条数（100）限制");
            }
            this.saveBatch(list);
            uploadInfo.setSuccessNum(list.size());
        }
        return uploadInfo;
    }

    @Override
    public Integer getCultureTextSettingCount() {

        return getDbCount().intValue();
    }

    private Long getDbCount() {
        LambdaQueryWrapper<CultureTextSetting> queryWrapper = new LambdaQueryWrapper<CultureTextSetting>()
                .eq(CultureTextSetting::getDeleteMark, ConstantUtil.NUM_FALSE);
        return cultureTextSettingMapper.selectCount(queryWrapper);
    }

    /**
     * 检查内容是否符合规范
     * @param row 行
     * @param col 列(0: 标题, 1: 内容)
     * @param str 内容
     * @param wordLimit 允许字数
     * @return java.lang.String
     */
    private String checkStr(int row, int col, String str, int wordLimit, String errorMsg) {

        String msg = "";
        // 判断内容是否为空
        if (StringUtil.isEmpty(str)) {
            msg += col == 0 ? "无文化标题" : "无文化内容 ";
        }
        // 判断字数是否超过限制
        int realLength = str.codePointCount(0, str.length());
        if (realLength > wordLimit) {
            msg += col == 0 ? "文化标题超过字数(" + wordLimit + ")上限" : "文化内容超过字数(" + wordLimit + ")上限 ";
        }
        // 判断是否包含emoji表情
        if (containsEmoji(str)) {
            msg += col == 0 ? "文化标题中包含emoji表情" : "文化内容中包含emoji表情 ";
        }
        if (StringUtil.isEmpty(errorMsg) && StringUtil.isNotEmpty(msg)) {
            msg = "第" + (row + 1) + "行 " + msg;
        }
        return msg;
    }

    public boolean containsEmoji(String text) {
        if (text == null) {
            return false;
        }
        return EMOJI_PATTERN.matcher(text).find();
    }
}
