package com.usky.oa.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.datascope.context.DataScopeContextHolder;
import com.usky.common.core.bean.CommonPage;
import com.usky.common.core.exception.BusinessException;
import com.usky.common.security.utils.SecurityUtils;
import com.usky.oa.domain.*;
import com.usky.oa.mapper.*;
import com.usky.oa.service.OaFormDefinitionService;
import com.usky.common.mybatis.core.AbstractCrudService;
import com.usky.oa.service.utils.OaApprovalGeneration;
import com.usky.oa.service.vo.OaFormNameResponseVO;
import com.usky.system.domain.SysUser;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 表单定义表 服务实现类
 * </p>
 *
 * @author fu
 * @since 2024-12-10
 */
@Service
public class OaFormDefinitionServiceImpl extends AbstractCrudService<OaFormDefinitionMapper, OaFormDefinition> implements OaFormDefinitionService {

    @Autowired
    private OaFormDefinitionMapper oaFormDefinitionMapper;

    @Autowired
    private OaDocumentMapper oaDocumentMapper;

    @Autowired
    private OaFlowMapper oaFlowMapper;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private OaNodeMapper nodeMapper;
    @Autowired
    private OaApprovalGeneration oaApprovalGeneration;

    /**
     * 新增/更新 表单
     * 此方法负责验证表单定义的合法性，包括表单名称和标识的唯一性、长度限制，并最终保存合法的表单定义
     * @param oaFormDefinition 表单定义对象，包含表单的详细信息
     * @throws BusinessException 当表单名称或标识不符合规范或已存在时抛出
     */
    @Transactional
    @Override
    public void addForm(OaFormDefinition oaFormDefinition) {

        String formName = oaFormDefinition.getFormName();
        String formSign = oaFormDefinition.getFormSign();
        String formExplain = oaFormDefinition.getFormExplain();
        // 判断 表单名称、标识、说明 是否为空或超长
        validateFormProperties(formName, formSign, formExplain);

        // 判断 表单分组 是否为空、有效
        isValidFormGroup(oaFormDefinition.getFormGroup());

        if (Objects.isNull(oaFormDefinition.getFormType())) {
            throw new BusinessException("表单字段信息不能为空");
        } else if (oaFormDefinition.getFormType() < 0 || oaFormDefinition.getFormType() > 1) {
            throw new BusinessException("表单类型不正确");
        }

        // 判断 表单可见范围 是否为空、有效
        validFromScope(oaFormDefinition);

        // 获取用户基本信息
        Integer tenantId = SecurityUtils.getTenantId();
        String username = SecurityUtils.getUsername();
        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
        LocalDateTime now = LocalDateTime.now();

        // 判断表单是新增或者修改
        if (oaFormDefinition.getId() == null) {
            // BeanUtils.copyBeanProp(oaFormDefinition, oaFormDefinition);
            // 判断表单名称和标识是否重复
            selectByNameOrSign(formName, formSign);
            oaFormDefinition.setCreateBy(username);
            oaFormDefinition.setDeptId(deptId);
            oaFormDefinition.setTenantId(tenantId);
            oaFormDefinition.setCreateTime(now);
            oaFormDefinition.setFormVersion(1);
            oaFormDefinition.setFormStatus(2);
            oaFormDefinitionMapper.insert(oaFormDefinition);
            oaApprovalGeneration.addGenerate(oaFormDefinition);
        } else {
            oaFormDefinition.setUpdateBy(username);
            oaFormDefinition.setUpdateTime(now);

            OaFormDefinition oaFormDefinition1 = oaFormDefinitionMapper.selectById(oaFormDefinition.getId());
            // 判断表单版本号是否需要更新
            if (versionUpdateValid(oaFormDefinition)) {
                oaFormDefinition.setFormVersion(oaFormDefinition1.getFormVersion() + 1);
            }
            if (!Objects.equals(oaFormDefinition.getFormSign(), oaFormDefinition1.getFormSign())) {
                throw new BusinessException("表单标识不可修改！");
            }

            // 校验是否能够进行修改
            selectIsHaveDocument(formSign, tenantId);
            oaFormDefinitionMapper.updateById(oaFormDefinition);
            oaApprovalGeneration.updateGenerate(oaFormDefinition);
        }
    }

    // 更新时表单下存在已生成单据时，不允许修改表单任何信息
    private void selectIsHaveDocument(String formSign, Integer tenantId) {
        LambdaQueryWrapper<OaDocument> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(OaDocument::getTenantId, tenantId)
                .eq(OaDocument::getType, formSign);
        List<OaDocument> oaDocument = oaDocumentMapper.selectList(queryWrapper);
        if (!oaDocument.isEmpty()) {
            throw new BusinessException("当前表单下已存在单据，不可修改！");
        }
    }

    /**
     * 删除表单
     * @param formId 表单ID，用于删除特定的表单定义
     */
    @Override
    public void delForm(Integer formId) {
        if (formId > 0) {
            OaFormDefinition oaFormDefinition = oaFormDefinitionMapper.selectById(formId);
            if (oaFormDefinition == null) {
                throw new BusinessException("表单不存在!");
            }
            if (validDelete(formId) != null) {
                throw new BusinessException("当前表单下存在单据，不可删除！");
            }
            oaFormDefinitionMapper.deleteById(oaFormDefinition);
        } else {
            throw new BusinessException("表单ID不能为空或者小于0");
        }
    }

    // 判断表单下是否存在已生成单据
    private OaDocument validDelete(Integer formId) {
        LambdaQueryWrapper<OaDocument> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(OaDocument::getFormId, formId);
        return oaDocumentMapper.selectOne(queryWrapper);
    }


    // 表单管理-分页查询
    @Override
    public CommonPage<OaFormDefinition> pageList(Integer formId, String formName, Integer formGroup, Integer formStatus, Integer pageNum, Integer pageSize) {
        IPage<OaFormDefinition> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<OaFormDefinition> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(formId != null, OaFormDefinition::getId, formId)
                .like(StringUtils.isNotBlank(formName), OaFormDefinition::getFormName, formName)
                .eq(formGroup != null, OaFormDefinition::getFormGroup, formGroup)
                .eq(formStatus != null, OaFormDefinition::getFormStatus, formStatus)
                .orderByDesc(OaFormDefinition::getId)
                // 数据权限控制
                .apply(Objects.nonNull(DataScopeContextHolder.getDataScopeSql()), DataScopeContextHolder.getDataScopeSql());
        page = oaFormDefinitionMapper.selectPage(page, queryWrapper);
        setCreateByNickName(page.getRecords());

        return new CommonPage<>(page.getRecords(), page.getTotal(), pageSize, pageNum);
    }

    // 真实姓名替换创建人userName
    private void setCreateByNickName(List<OaFormDefinition> records) {
        if (records == null || records.isEmpty()) {
            return;
        }

        List<String> createByList = records.stream()
                .map(OaFormDefinition::getCreateBy)
                .filter(StringUtils::isNotBlank)
                .distinct()
                .collect(Collectors.toList());

        Map<String, String> createByNickNameMap = new HashMap<>();
        if (!createByList.isEmpty()) {
            LambdaQueryWrapper<SysUser> userQueryWrapper = Wrappers.lambdaQuery();
            userQueryWrapper.in(SysUser::getUserName, createByList)
                    .eq(SysUser::getTenantId, SecurityUtils.getTenantId())
                    .eq(SysUser::getDelFlag, 0)
                    .eq(SysUser::getStatus, 0)
                    .select(SysUser::getUserName, SysUser::getNickName);
            List<SysUser> sysUsers = sysUserMapper.selectList(userQueryWrapper);
            createByNickNameMap = sysUsers.stream()
                    .collect(Collectors.toMap(SysUser::getUserName, SysUser::getNickName));
        }

        for (OaFormDefinition record : records) {
            String createBy = record.getCreateBy();
            if (StringUtils.isNotBlank(createBy) && createByNickNameMap.containsKey(createBy)) {
                record.setCreateBy(createByNickNameMap.get(createBy));
            }
        }
    }

    // 表单管理-修改表单状态
    @Override
    public void validUpdateStatus(Integer formId, Integer formStatus) {
        if (formId == null || formId <= 0) {
            throw new BusinessException("表单ID不能为空或者小于0！");
        }
        OaFormDefinition oaFormDefinition = oaFormDefinitionMapper.selectById(formId);
        if (oaFormDefinition == null) {
            throw new BusinessException("表单不存在!");
        }

        if (formStatus == null || formStatus < 1 || formStatus > 2) {
            throw new BusinessException("表单状态为空或不在设定值范围！");
        }
        oaFormDefinition.setFormStatus(formStatus);
        oaFormDefinitionMapper.updateById(oaFormDefinition);
    }

    // 我的申请-根据权限查询表单
    @Override
    public List<OaFormDefinition> selectByScope(String formSign) {
        Long userId = SecurityUtils.getUserId();
        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
        Integer tenantId = SecurityUtils.getTenantId();

        List<OaFormDefinition> oaFormDefinitions = new ArrayList<>();

        LambdaQueryWrapper<OaFormDefinition> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(OaFormDefinition::getTenantId, tenantId);

        if (StringUtils.isNotBlank(formSign)) {
            queryWrapper.eq(OaFormDefinition::getFormSign, formSign);
            OaFormDefinition oaFormDefinition = oaFormDefinitionMapper.selectOne(queryWrapper);
            if (oaFormDefinition != null) {
                oaFormDefinitions.add(oaFormDefinition);
            }
            return oaFormDefinitions;
        }

        queryWrapper.eq(OaFormDefinition::getFormStatus, 1)
                .and(qw -> qw
                        .eq(OaFormDefinition::getFormScope, 1)
                        .or()
                        .apply("FIND_IN_SET('" + deptId + "', dept_ids) > 0")
                        .or()
                        .apply("FIND_IN_SET('" + userId + "', user_ids) > 0"));
        oaFormDefinitions = oaFormDefinitionMapper.selectList(queryWrapper);
        return oaFormDefinitions;
    }

    // 表单管理-根据权限查询表单
    @Override
    public List<OaFormNameResponseVO> getFormName(String formSign, String formName, Integer formId) {
        Long userId = SecurityUtils.getUserId();
        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
        Integer tenantId = SecurityUtils.getTenantId();
        LambdaQueryWrapper<OaFormDefinition> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(OaFormDefinition::getId, OaFormDefinition::getFormName, OaFormDefinition::getFormSign)
                .eq(OaFormDefinition::getTenantId, tenantId)
                .eq(StringUtils.isNotBlank(formSign), OaFormDefinition::getFormSign, formSign)
                .eq(StringUtils.isNotBlank(formName), OaFormDefinition::getFormName, formName)
                .eq(formId != null && formId > 0, OaFormDefinition::getId, formId)
                .eq(OaFormDefinition::getFormStatus, 1)
                .and(qw -> qw
                        .eq(OaFormDefinition::getFormScope, 1)
                        .or()
                        .apply("FIND_IN_SET('" + deptId + "', dept_ids) > 0")
                        .or()
                        .apply("FIND_IN_SET('" + userId + "', user_ids) > 0"));
        List<OaFormDefinition> oaFormDefinitions = oaFormDefinitionMapper.selectList(queryWrapper);

        List<OaFormNameResponseVO> formNameList = new ArrayList<>();
        for (OaFormDefinition oaFormDefinition : oaFormDefinitions) {
            OaFormNameResponseVO oaFormNameResponseVO = new OaFormNameResponseVO();
            oaFormNameResponseVO.setFormId(oaFormDefinition.getId());
            oaFormNameResponseVO.setFormName(oaFormDefinition.getFormName());
            oaFormNameResponseVO.setFormSign(oaFormDefinition.getFormSign());
            formNameList.add(oaFormNameResponseVO);
        }
        return formNameList;
    }


    // 表单版本更新验证
    private Boolean versionUpdateValid(OaFormDefinition oaFormDefinition) {
        boolean update = false;
        OaFormDefinition selectOne = oaFormDefinitionMapper.selectById(oaFormDefinition.getId());
        if (!selectOne.getFlowInfo().equals(oaFormDefinition.getFlowInfo()) || !selectOne.getFormExplain().equals(oaFormDefinition.getFormExplain())) {
            update = true;
        }
        return update;
    }

    /**
     * 根据表单id、名称查询
     * @param formName 表单名称，用于查询特定的表单定义
     * @return 返回查询到的表单定义对象，如果没有找到匹配的表单，则返回null
     */
    public void selectByNameOrSign(String formName, String formSign) {
        LambdaQueryWrapper<OaFormDefinition> queryName = Wrappers.lambdaQuery();
        queryName.eq(StringUtils.isNotBlank(formName), OaFormDefinition::getFormName, formName);
        OaFormDefinition fromByName = oaFormDefinitionMapper.selectOne(queryName);

        LambdaQueryWrapper<OaFormDefinition> querySign = Wrappers.lambdaQuery();
        querySign.eq(StringUtils.isNotBlank(formSign), OaFormDefinition::getFormSign, formSign);
        OaFormDefinition fromBySign = oaFormDefinitionMapper.selectOne(querySign);

        if (fromByName != null) {
            throw new BusinessException("表单名称已存在，请更换");
        } else if (fromBySign != null) {
            throw new BusinessException("表单标识已存在，请更换");
        }
    }

    // 表单管理-表单属性(表单名称、标识、说明)验证
    private void validateFormProperties(String formName, String formSign, String formExplain) {
        // 判断表单名称是否为空或者超长
        if (StringUtils.isBlank(formName) || formName.length() > 10) {
            throw new BusinessException("表单名称不能为空或空字符串");
        }

        // 判断表单标识是否为空或者超长
        if (StringUtils.isBlank(formSign)) {
            throw new BusinessException("表单标识不能为空");
        } else if (formSign.length() < 3 || formSign.length() > 4) {
            throw new BusinessException("表单标识长度不能少于3个字符或超过4个字符");
        } else if (!formSign.matches("^[A-Z]+$")) {
            throw new BusinessException("表单标识只能包含大写字母！");
        }

        // 判断表单说明是否超长
        if (StringUtils.isNotBlank(formExplain) && formExplain.length() > 100) {
            throw new BusinessException("表单说明长度不能超过100个字符");
        }
    }

    // 判断表单所在分组是否有效
    private void isValidFormGroup(Integer formGroup) {
        if (formGroup == null) {
            throw new BusinessException("表单所在分组不能为空");
        } else if (formGroup < 0 || formGroup > 6) {
            throw new BusinessException("表单所在分组异常！请联系管理员");
        }
    }

    // 校验表单可见范围是否有效
    private void validFromScope(OaFormDefinition oaFormDefinition) {
        if (oaFormDefinition.getFormScope() == null) {
            throw new BusinessException("表单可见范围不能为空");
        } else {
            Integer formScope = oaFormDefinition.getFormScope();
            String deptIds = oaFormDefinition.getDeptIds();
            String userIds = oaFormDefinition.getUserIds();
            switch (formScope) {
                case 0:
                    if (StringUtils.isBlank(deptIds)) {
                        throw new BusinessException("表单可见范围为部门，部门集合不能为空");
                    } else if (!deptIds.matches("^(?:\\d+)(,\\d+)*$")) {
                        throw new BusinessException("部门集合格式不正确！");
                    }
                    break;

                case 1:
                    break;

                case 2:
                    if (StringUtils.isBlank(userIds)) {
                        throw new BusinessException("表单可见范围为人员，人员集合不能为空");
                    } else if (!userIds.matches("^(?:\\d+)(,\\d+)*$")) {
                        throw new BusinessException("人员集合格式不正确！");
                    }
                    break;
                default:
                    throw new BusinessException("表单可见范围为异常！请联系管理员");
            }
        }

    }

}
