package com.usky.oa.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.*;
import com.usky.common.mybatis.core.AbstractCrudService;
import com.usky.oa.service.utils.OaSendMessageCenter;
import com.usky.system.domain.SysUser;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 单据总表 服务实现类
 * </p>
 *
 * @author fu
 * @since 2024-12-26
 */
@Service
public class OaDocumentServiceImpl extends AbstractCrudService<OaDocumentMapper, OaDocument> implements OaDocumentService {

    @Autowired
    private OaDocumentMapper oaDocumentMapper;

    @Autowired
    private OaQjdDocumentMapper oaQjdDocumentMapper;

    @Autowired
    private OaQjdDocumentService oaQjdDocumentService;

    @Autowired
    private OaJbdDocumentService oaJbdDocumentService;

    @Autowired
    private OaJbdDocumentMapper oaJbdDocumentMapper;

    @Autowired
    private OaCgdDocumentService oaCgdDocumentService;

    @Autowired
    private OaCgdDocumentMapper oaCgdDocumentMapper;

    @Autowired
    private OaDocumentMapper documentMapper;

    @Autowired
    private OaFormDefinitionMapper oaFormDefinitionMapper;

    @Autowired
    private OaApprovalMapper oaApprovalMapper;

    @Autowired
    private OaSendMessageCenter oaSendMessageCenter;

    @Autowired
    private SysUserMapper sysUserMapper;

    @Autowired
    private OaFbdDocumentService oaFbdDocumentService;

    @Autowired
    private OaFbdDocumentMapper oaFbdDocumentMapper;

    private static final String TABLE_HEAD = "oa_";
    private static final String TABLE_SUFFIX = "_document";
    // 消息通知：提醒
    private static final int INFO_TYPE = 3;

    // 我的申请
    @Override
    public CommonPage<OaDocument> myApplication(String docNo, String type, Integer status,
                                                String startTime, String endTime,
                                                Integer pageNum, Integer pageSize) {
        // 获取当前用户信息
        Long userId = SecurityUtils.getUserId();
        Integer tenantId = SecurityUtils.getTenantId();
        String username = SecurityUtils.getLoginUser().getSysUser().getNickName();

        // 设置默认分页参数
        pageNum = (pageNum == null || pageNum <= 0) ? 1 : pageNum;
        pageSize = (pageSize == null || pageSize <= 0) ? 10 : pageSize;

        // 构建查询条件
        LambdaQueryWrapper<OaDocument> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(OaDocument::getTenantId, tenantId)
                .eq(OaDocument::getProposer, userId)
                .like(StringUtils.isNotBlank(docNo), OaDocument::getDocNo, docNo)
                .eq(StringUtils.isNotBlank(type), OaDocument::getType, type)
                .eq(status != null, OaDocument::getDocStatus, status)
                .between(StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime),
                        OaDocument::getCreateTime, startTime, endTime)
                .orderByDesc(OaDocument::getId);

        Page<OaDocument> page = new Page<>(pageNum, pageSize);
        Page<OaDocument> resultPage = documentMapper.selectPage(page, wrapper);

        if (resultPage.getRecords().isEmpty()) {
            return new CommonPage<>();
        }

        resultPage.getRecords().forEach(document -> document.setCreateBy(username));

        return toCommonPage(resultPage);
    }

    private CommonPage<OaDocument> toCommonPage(Page<OaDocument> page) {
        return new CommonPage<>(
                page.getRecords(),
                page.getTotal(),
                page.getSize(),
                page.getCurrent()
        );
    }

    // 单据详情
    @Override
    public Object documentDetails(String docNo) {
        Object documentDetails = null;
        String type = getFormSign(docNo);
        String fieldInfo = oaFormDefinitionMapper.selectOne(Wrappers.lambdaQuery(OaFormDefinition.class).eq(OaFormDefinition::getFormSign, type)).getFieldInfo();

        switch (fieldInfo) {
            case "QJD":
                OaQjdDocument oaQjdDocument = oaQjdDocumentMapper.selectOne(Wrappers.lambdaQuery(OaQjdDocument.class).eq(OaQjdDocument::getDocNo, docNo));
                oaQjdDocument.setCreateBy(getNickName(oaQjdDocument.getProposer()));
                documentDetails = oaQjdDocument;
                break;
            case "JBD":
                OaJbdDocument oaJbdDocument = oaJbdDocumentMapper.selectOne(Wrappers.lambdaQuery(OaJbdDocument.class).eq(OaJbdDocument::getDocNo, docNo));
                oaJbdDocument.setCreateBy(getNickName(oaJbdDocument.getProposer()));
                documentDetails = oaJbdDocument;
                break;
            case "CGD":
                OaCgdDocument oaCgdDocument = oaCgdDocumentMapper.selectOne(Wrappers.lambdaQuery(OaCgdDocument.class).eq(OaCgdDocument::getDocNo, docNo));
                oaCgdDocument.setCreateBy(getNickName(oaCgdDocument.getProposer()));
                documentDetails = oaCgdDocument;
                break;
            case "FBD":
                OaFbdDocument oaFbdDocument = oaFbdDocumentMapper.selectOne(Wrappers.lambdaQuery(OaFbdDocument.class).eq(OaFbdDocument::getDocNo, docNo));
                oaFbdDocument.setCreateBy(getNickName(oaFbdDocument.getProposer()));
                documentDetails = oaFbdDocument;
                break;
        }

        if (documentDetails == null) {
            throw new BusinessException("单据不存在");
        }

        return documentDetails;
    }

    // 获取用户姓名
    private String getNickName(Long userId) {
        LambdaQueryWrapper<SysUser> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(SysUser::getNickName).eq(SysUser::getUserId, userId);
        return sysUserMapper.selectOne(queryWrapper).getNickName();
    }

    // 删除单据
    @Override
    public void delDocument(String docNo) {
        String type = getFormSign(docNo);
        switch (type) {
            case "QJD":
                oaQjdDocumentMapper.delete(Wrappers.lambdaQuery(OaQjdDocument.class).eq(OaQjdDocument::getDocNo, docNo));
                break;
            case "JBD":
                oaJbdDocumentMapper.delete(Wrappers.lambdaQuery(OaJbdDocument.class).eq(OaJbdDocument::getDocNo, docNo));
                break;
            case "CGD":
                oaCgdDocumentMapper.delete(Wrappers.lambdaQuery(OaCgdDocument.class).eq(OaCgdDocument::getDocNo, docNo));
                break;
            case "FBD":
                oaFbdDocumentMapper.delete(Wrappers.lambdaQuery(OaFbdDocument.class).eq(OaFbdDocument::getDocNo, docNo));
                break;
        }
        oaDocumentMapper.delete(Wrappers.lambdaQuery(OaDocument.class).eq(OaDocument::getDocNo, docNo));
    }

    // 新增单据
    @Transactional
    @Override
    public void addDoc(JSONObject oaDocument) {
        LambdaQueryWrapper<OaFormDefinition> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(OaFormDefinition::getFieldInfo).eq(OaFormDefinition::getId, oaDocument.get("formId"));
        OaFormDefinition oaFormDefinition = oaFormDefinitionMapper.selectOne(queryWrapper);

        JSONObject node = oaDocument.getJSONObject("node");

        if (oaFormDefinition == null) {
            throw new BusinessException("新增表单模板不存在！请联系管理员");
        }
        String sign = oaFormDefinition.getFieldInfo();

        switch (sign) {
            case "QJD":
                oaQjdDocumentService.addQjDocument(JSON.parseObject(oaDocument.toJSONString(), OaQjdDocument.class));
                break;
            case "JBD":
                oaJbdDocumentService.add(JSON.parseObject(oaDocument.toJSONString(), OaJbdDocument.class));
                break;
            case "CGD":
                oaCgdDocumentService.add(JSON.parseObject(oaDocument.toJSONString(), OaCgdDocument.class));
                break;
            case "FBD":
                oaFbdDocumentService.addOrUpDate(JSON.parseObject(oaDocument.toJSONString(), OaFbdDocument.class), node);
                break;
            default:
                throw new BusinessException("新增表单模板不存在！请联系管理员");
        }
    }

    // 更新单据
    @Transactional
    @Override
    public void updateDoc(JSONObject jsonDocument) {
        LambdaQueryWrapper<OaFormDefinition> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.select(OaFormDefinition::getFieldInfo).eq(OaFormDefinition::getId, jsonDocument.get("formId"));
        OaFormDefinition oaFormDefinition = oaFormDefinitionMapper.selectOne(queryWrapper);
        String sign = oaFormDefinition.getFieldInfo();

        JSONObject node = jsonDocument.getJSONObject("node");

        switch (sign) {
            case "QJD":
                oaQjdDocumentService.updateQjDocument(JSON.parseObject(jsonDocument.toJSONString(), OaQjdDocument.class));
                break;
            case "JBD":
                oaJbdDocumentService.update(JSON.parseObject(jsonDocument.toJSONString(), OaJbdDocument.class));
                break;
            case "CGD":
                oaCgdDocumentService.update(JSON.parseObject(jsonDocument.toJSONString(), OaCgdDocument.class));
                break;
            case "FBD":
                oaFbdDocumentService.addOrUpDate(JSON.parseObject(jsonDocument.toJSONString(), OaFbdDocument.class), node);
                break;
            default:
                throw new BusinessException("单据模板不存在！请联系管理员");
        }
    }

    // 提交单据
    @Transactional
    @Override
    public void submit(String docNo, Integer docStatus) {
        if (docStatus != 1) {
            throw new RuntimeException("单据提交异常，请联系管理员！");
        } else {
            LambdaQueryWrapper<OaDocument> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(OaDocument::getDocNo, docNo);
            OaDocument oaDocument = oaDocumentMapper.selectOne(queryWrapper);
            if (oaDocument.getDocStatus() == 1) {
                throw new RuntimeException("单据已提交，请勿重复提交！");
            }
        }

        Long deptId = SecurityUtils.getLoginUser().getSysUser().getDeptId();
        Integer tenantId = SecurityUtils.getTenantId();
        String username = SecurityUtils.getUsername();
        Long userId = SecurityUtils.getUserId();
        LocalDateTime now = LocalDateTime.now();

        String formSign = getFormSign(docNo);
        formSign = oaFormDefinitionMapper.selectOne(Wrappers.lambdaQuery(OaFormDefinition.class).eq(OaFormDefinition::getFormSign, formSign)).getFieldInfo();

        switch (formSign) {
            case "QJD":
                oaQjdDocumentMapper.update(null, Wrappers.lambdaUpdate(OaQjdDocument.class)
                        .set(OaQjdDocument::getDocStatus, docStatus)
                        .set(OaQjdDocument::getUpdateBy, username)
                        .set(OaQjdDocument::getUpdateTime, now)
                        .eq(OaQjdDocument::getDocNo, docNo));
                break;
            case "JBD":
                oaJbdDocumentMapper.update(null, Wrappers.lambdaUpdate(OaJbdDocument.class)
                        .set(OaJbdDocument::getDocStatus, docStatus)
                        .set(OaJbdDocument::getUpdateBy, username)
                        .set(OaJbdDocument::getUpdateTime, now)
                        .eq(OaJbdDocument::getDocNo, docNo));
                break;
            case "CGD":
                oaCgdDocumentMapper.update(null, Wrappers.lambdaUpdate(OaCgdDocument.class)
                        .set(OaCgdDocument::getDocStatus, docStatus)
                        .set(OaCgdDocument::getUpdateBy, username)
                        .set(OaCgdDocument::getUpdateTime, now)
                        .eq(OaCgdDocument::getDocNo, docNo));
                break;
            case "FBD":
                oaFbdDocumentMapper.update(null, Wrappers.lambdaUpdate(OaFbdDocument.class)
                        .set(OaFbdDocument::getDocStatus, docStatus)
                        .set(OaFbdDocument::getUpdateBy, username)
                        .set(OaFbdDocument::getUpdateTime, now)
                        .eq(OaFbdDocument::getDocNo, docNo));
                oaFbdDocumentService.getOaApproval(oaFbdDocumentMapper.selectOne(Wrappers.lambdaQuery(OaFbdDocument.class).eq(OaFbdDocument::getDocNo, docNo)));
                break;
        }
        oaDocumentMapper.update(null, Wrappers.lambdaUpdate(OaDocument.class)
                .set(OaDocument::getDocStatus, docStatus)
                .set(OaDocument::getUpdateBy, username)
                .set(OaDocument::getUpdateTime, now)
                .eq(OaDocument::getDocNo, docNo));
    }

    // 获取单据类型
    private String getFormSign(String docNo) {
        if (StringUtils.isBlank(docNo)) {
            throw new RuntimeException("单据号不能为空！");
        } else if (docNo.split("-").length != 2 ||
                docNo.split("-")[0].length() > 4 ||
                docNo.split("-")[0].length() < 3 ||
                docNo.split("-")[1].length() != 12) {
            throw new RuntimeException("单据号格式错误！");
        }
        return docNo.split("-")[0];
    }

}
