package com.yh.saas.plugin.news.service.impl;


import com.alibaba.fastjson.JSON;
import com.alipay.sofa.runtime.api.annotation.SofaReference;
import com.alipay.sofa.runtime.api.annotation.SofaService;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.winsea.svc.base.base.entity.*;
import com.winsea.svc.base.base.service.*;
import com.winsea.svc.base.base.util.tree.TreeWrapper;
import com.winsea.svc.base.security.entity.User;
import com.winsea.svc.base.security.util.AuthSecurityUtils;
import com.yh.saas.plugin.news.entity.AnnoIssueInfo;
import com.yh.saas.plugin.news.entity.AnnoReadUserInfo;
import com.yh.saas.plugin.news.entity.CommonAnnouncementIssueInfo;
import com.yh.saas.plugin.news.entity.Recipient;
import com.yh.saas.plugin.news.entity.view.DeptStaffTreeView;
import com.yh.saas.plugin.news.exception.EnterpriseErrorCodeEnums;
import com.yh.saas.plugin.news.mapper.NewsAnnoIssueInfoMapper;
import com.yh.saas.plugin.news.mapper.NewsAnnouncementIssueInfoMapper;
import com.yh.saas.plugin.news.service.IAnnoIssueInfoService;
import com.yh.saas.plugin.news.service.INewsAnnoReadUserInfoService;
import com.yh.saas.plugin.news.util.thread.ObservableRunnable;
import com.yh.saas.plugin.news.util.thread.ThreadLifeCycleObserver;
import com.yh.saas.common.support.util.IdGenerator;
import com.yh.saas.common.support.util.uniqueness.UniquenessChecker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * <p>
 * 公告模块 - 公告详情 - 业务实现类
 * </p>
 *
 * @Auther ZhangMingYu
 * @since 2019年8月14日15:59:36
 */
@Slf4j
@SofaService
public class NewsAnnoIssueInfoServiceImpl extends ServiceImpl<NewsAnnoIssueInfoMapper, AnnoIssueInfo> implements IAnnoIssueInfoService {

    @Autowired
    private NewsAnnoIssueInfoMapper annoIssueInfoMapper;

    @Autowired
    private INewsAnnoReadUserInfoService readUserInfoService;

    @SofaReference
    private ICommonStaffService staffService;

    @SofaReference
    private ICommonDepartmentService departmentService;

    @SofaReference
    private ICommonCompanyService companyService;

    @SofaReference
    private ICommonRoleService roleService;

    @SofaReference
    private ICommonStaffRoleService staffRoleService;

    @SofaReference
    private IAppendixService appendixService;

    @SofaReference
    private ICommonTenantService commonTenantService;

    @Autowired
    private NewsAnnouncementIssueInfoMapper announcementIssueInfoMapper;

    private static ExecutorService executor = Executors.newFixedThreadPool(5);

    @Override
    public String test() {
        return (String) SecurityUtils.getSubject().getPrincipal();
    }

    /**
     * 公告 待发布 待接收一览
     *
     * @param annoIssueInfo 查询条件
     * @return
     */
    @Override
    public Page<AnnoIssueInfo> queryPage(AnnoIssueInfo annoIssueInfo) {
        // 当前登录人主要角色
        CommonStaffRole staffRole = staffRoleService.getMajorRole(AuthSecurityUtils.getCurrentUserInfo().getUserId());
        annoIssueInfo.setCompId(AuthSecurityUtils.getCurrentUserInfo().getCompId());
        annoIssueInfo.setLoginDeptId(roleService.selectById(staffRole.getRoleId()).getDeptId());
        Page<AnnoIssueInfo> annoIssueInfoPage = annoIssueInfo.getQueryPage();
        List<AnnoIssueInfo> announcementVos = annoIssueInfoMapper.queryPage(annoIssueInfo, annoIssueInfoPage);
        announcementVos.forEach(e -> {
            if (StringUtils.isNotBlank(e.getOssCoverUrl())) {
                CommonAppendix commonAppendix = appendixService.selectById(e.getOssCoverUrl());
                if (commonAppendix != null) {
                    e.setCoverUrl(commonAppendix.getAppendixPath());
                }
            }
            //查询阅读数
            Integer readCount = baseMapper.getCountByCondition(e.getId());
            e.setReadCount(readCount);
        });
        return annoIssueInfoPage.setRecords(announcementVos);
    }

    /**
     * 首页新闻查询
     *
     * @param annoIssueInfo 查询条件
     * @return
     */
    @Override
    public List<AnnoIssueInfo> queryHomePage(AnnoIssueInfo annoIssueInfo) {
        // 当前登录人主要角色
        User currentUserInfo = AuthSecurityUtils.getCurrentUserInfo();
        String userId = currentUserInfo.getUserId();
        String compId = currentUserInfo.getCompId();
        if (StringUtils.isNotBlank(annoIssueInfo.getLoginUserId())) {
            userId = annoIssueInfo.getLoginUserId();
        }
        if (StringUtils.isNotBlank(annoIssueInfo.getCompId())) {
            compId = annoIssueInfo.getCompId();
        }
        annoIssueInfo.setCompId(compId);
        CommonStaffRole staffRole = staffRoleService.getMajorRole(userId);
        CommonRole commonRole = roleService.selectById(staffRole.getRoleId());
        annoIssueInfo.setLoginDeptId(commonRole.getDeptId());
        annoIssueInfo.setCoverUrl("1");
        annoIssueInfo.setCurrentPage(1);
        annoIssueInfo.setPageSize(3);
        Page<AnnoIssueInfo> annoIssueInfoPage = annoIssueInfo.getQueryPage();
        List<AnnoIssueInfo> announcementVos = annoIssueInfoMapper.queryPage(annoIssueInfo, annoIssueInfoPage);
        announcementVos.forEach(e -> {
            if (StringUtils.isNotBlank(e.getOssCoverUrl())) {
                CommonAppendix commonAppendix = appendixService.selectById(e.getOssCoverUrl());
                if (commonAppendix != null) {
                    e.setCoverUrl(commonAppendix.getAppendixPath());
                }
            }
        });
        return announcementVos;
    }

    /**
     * 查询详情
     *
     * @param annoIssueInfo 查询条件
     * @return
     */
    @Override
    public AnnoIssueInfo queryInfo(AnnoIssueInfo annoIssueInfo) {
        AnnoIssueInfo issueInfo = selectById(annoIssueInfo);

        if (!StringUtils.isEmpty(issueInfo.getReleaseRange())) {
            List<CommonDepartment> departmentList = new ArrayList<>();
            List<Recipient> recipients = JSON.parseArray(issueInfo.getReleaseRange(), Recipient.class);
            for (Recipient recipient : recipients) {
                for (String userIds : recipient.getUserIds()) {
                    CommonDepartment department = departmentService.selectOne(new EntityWrapper<CommonDepartment>()
                            .eq(CommonDepartment.QueryFields.DEPT_ID, userIds));

                    if (null != department) {
                        department.setUnderCompName(companyService.selectOne(new EntityWrapper<CommonCompany>()
                                .eq(CommonCompany.QueryFields.COMP_ID, department.getUnderCompId())).getCompName());
                        departmentList.add(department);
                    }
                }
            }
            issueInfo.setDepartments(departmentList);
        }

        AnnoReadUserInfo annoReadUserInfo = new AnnoReadUserInfo();
        annoReadUserInfo.setReadUserId(AuthSecurityUtils.getCurrentUserInfo().getUserId());
        annoReadUserInfo.setAnnouncementId(annoIssueInfo.getId());
        readUserInfoService.haveSee(annoReadUserInfo);

        return issueInfo;
    }

    @Override
    @Transactional
    public boolean create(AnnoIssueInfo annoIssueInfo) {
        annoIssueInfo.setId(IdGenerator.generateUUID());
        annoIssueInfo.setCompId(AuthSecurityUtils.getCurrentUserInfo().getCompId());
        annoIssueInfo.setIssueDate(new Date());

        List<Recipient> recipients = annoIssueInfo.getRecipients();
        annoIssueInfo.setReleaseRange(JSON.toJSONString(recipients));
        if (!StringUtils.isEmpty(AuthSecurityUtils.getCurrentUserInfo().getTenantId())) {
            CommonTenant commonTenant = commonTenantService.selectById(AuthSecurityUtils.getCurrentUserInfo().getTenantId());
            if (null != commonTenant) {
                annoIssueInfo.setTenantId(AuthSecurityUtils.getCurrentUserInfo().getTenantId());
                annoIssueInfo.setTenantName(commonTenant.getTenantName());
            }
        }

        if (!StringUtils.isEmpty(annoIssueInfo.getIsIssue()) && "1".equals(annoIssueInfo.getIsIssue())) {
            release(annoIssueInfo);
        }
        return this.insert(annoIssueInfo);
    }

    @Override
    @Transactional
    public void chagneInfo(AnnoIssueInfo annoIssueInfo) {
        AnnoIssueInfo annoIssue = selectById(annoIssueInfo.getId());
        annoIssueInfo.setIssueDate(new Date());
        if (!annoIssue.getIssueUserId().equals(AuthSecurityUtils.getCurrentUserInfo().getUserId())) {
            throw new UniquenessChecker.UniquenessException(EnterpriseErrorCodeEnums.ANNOUNCEMENT_NOT_ISSUE_USER_ID.getValue(), EnterpriseErrorCodeEnums.ANNOUNCEMENT_NOT_ISSUE_USER_ID.getDesc());
        }
        annoIssueInfo.setCompId(AuthSecurityUtils.getCurrentUserInfo().getCompId());
        List<Recipient> recipients = annoIssueInfo.getRecipients();
        annoIssueInfo.setReleaseRange(JSON.toJSONString(recipients));

        if (!StringUtils.isEmpty(annoIssueInfo.getIsIssue()) && "1".equals(annoIssueInfo.getIsIssue())) {
            release(annoIssueInfo);
        }

        updateById(annoIssueInfo);
    }

    @Override
    @Transactional
    public void remove(AnnoIssueInfo annoIssueInfo) {
        AnnoIssueInfo annoIssue = selectById(annoIssueInfo.getId());
        if (!annoIssue.getIssueUserId().equals(AuthSecurityUtils.getCurrentUserInfo().getUserId())) {
            throw new UniquenessChecker.UniquenessException(EnterpriseErrorCodeEnums.ANNOUNCEMENT_NOT_ISSUE_USER_ID.getValue(), EnterpriseErrorCodeEnums.ANNOUNCEMENT_NOT_ISSUE_USER_ID.getDesc());
        }
        this.deleteById(annoIssueInfo.getId());
        readUserInfoService.delete(new EntityWrapper<AnnoReadUserInfo>().eq(AnnoReadUserInfo.QueryFiles.ANNOUNCEMENT_ID, annoIssueInfo.getId()));
    }

    /**
     * 发布
     */
    private void release(AnnoIssueInfo annoIssueInfo) {
        List<Recipient> recipients = annoIssueInfo.getRecipients();
        List<AnnoReadUserInfo> annoReadUserInfos = new ArrayList<>();
        List<String> staffIdList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(recipients)) {
            // 循环页面上选中的部门
            recipients.forEach(recipient -> recipient.getUserIds().forEach(userId -> {
                List<CommonRole> roleList = roleService.findDeptRoleList(Arrays.asList(userId));// 根据部门查职务
                if (CollectionUtils.isNotEmpty(roleList)) {
                    // 根据职务查人
                    List<CommonStaffRole> staffRoleList = staffRoleService.findStaff(roleList.stream().map(CommonRole::getRoleId).collect(Collectors.toList()));
                    if (CollectionUtils.isNotEmpty(staffRoleList)) {
                        staffIdList.addAll(staffRoleList.stream().map(CommonStaffRole::getStaffId).collect(Collectors.toList()));
                    }
                }
            }));
            // 将新闻推送给人
            if (CollectionUtils.isNotEmpty(staffIdList)) {
                staffIdList.forEach(id -> {
                    AnnoReadUserInfo annoReadUserInfo = new AnnoReadUserInfo();
                    annoReadUserInfo.setAnnouncementId(annoIssueInfo.getId());
                    annoReadUserInfo.setReadUserId(id);
                    annoReadUserInfo.setId(IdGenerator.generateUUID());
                    annoReadUserInfo.setCompId(annoIssueInfo.getCompId());
                    annoReadUserInfos.add(annoReadUserInfo);
                    //开启线程池进行发送
                    executor.execute(() -> this.jpush(annoIssueInfo, annoReadUserInfo));
                });
                readUserInfoService.createAll(annoReadUserInfos);
            }
        }
    }

    /**
     * 获取公司下组织架构
     */
    @Override
    public List getCompDepaStaff() {
        String compId = AuthSecurityUtils.getCurrentUserInfo().getCompId();

        List<DeptStaffTreeView> deptStaffTreeViews = new ArrayList<>();
        //获取公司下所有部门

        CommonCompany company = companyService.selectOne(new EntityWrapper<CommonCompany>().eq(CommonCompany.QueryFields.COMP_ID, compId));

        DeptStaffTreeView deptStaffTreeView1 = new DeptStaffTreeView();
        deptStaffTreeView1.setId(company.getCompId());
        deptStaffTreeView1.setParentId("-1");
        deptStaffTreeView1.setName(company.getCompName());
        deptStaffTreeView1.setChildren(new ArrayList<>());
        deptStaffTreeViews.add(deptStaffTreeView1);

        List<CommonDepartment> departments = departmentService.selectList(new EntityWrapper<CommonDepartment>().eq(CommonDepartment.QueryFields.COMP_ID, compId));
        departments.forEach(department -> {
            DeptStaffTreeView deptStaffTreeView = new DeptStaffTreeView();
            deptStaffTreeView.setId(department.getDeptId());
            if (StringUtils.isEmpty(department.getParentDeptId())) {
                deptStaffTreeView.setParentId(department.getCompId());
            } else {
                deptStaffTreeView.setParentId(department.getParentDeptId());
            }
            deptStaffTreeView.setName(department.getDeptName());
            deptStaffTreeView.setChildren(new ArrayList<>());
            deptStaffTreeView.setStaffs(staffService.selectList(new EntityWrapper<CommonStaff>().eq(CommonStaff.QueryFields.DEPT_ID, department.getDeptId())));
            deptStaffTreeViews.add(deptStaffTreeView);
        });


        TreeWrapper<DeptStaffTreeView> deptStaffTreeViewTreeWrapper = new TreeWrapper<>(deptStaffTreeViews);


        return deptStaffTreeViewTreeWrapper.polymerize();
    }

    /**
     * 获取租户下公司部门
     */
    @Override
    public List<DeptStaffTreeView> getTenantCompDeptInfo() {
        String tenantId = AuthSecurityUtils.getCurrentUserInfo().getTenantId();// 租户id

        List<DeptStaffTreeView> deptStaffTreeViews = new ArrayList<>();
        List<CommonCompany> companyList = companyService.selectList(new EntityWrapper<CommonCompany>().eq(CommonCompany.QueryFields.TENANT_ID, tenantId));
        companyList.forEach(company -> {
            DeptStaffTreeView deptStaffTreeView1 = new DeptStaffTreeView();
            deptStaffTreeView1.setId(company.getCompId());
            deptStaffTreeView1.setParentId("-1");
            deptStaffTreeView1.setName(company.getCompName());

            //获取公司下所有部门
            List<CommonDepartment> departments = departmentService.selectList(new EntityWrapper<CommonDepartment>()
                    .eq(CommonDepartment.QueryFields.UNDER_COMP_ID, company.getCompId()));
            List<DeptStaffTreeView> childList = new ArrayList<>();
            departments.forEach(dept -> {
                DeptStaffTreeView deptDetail = new DeptStaffTreeView();
                deptDetail.setId(dept.getDeptId());
                deptDetail.setName(dept.getDeptName());
                childList.add(deptDetail);
            });
            deptStaffTreeView1.setChildren(childList);
            deptStaffTreeViews.add(deptStaffTreeView1);
        });
        return deptStaffTreeViews;
    }


    /**
     * 新增租户时发布新闻
     */
    @Override
    public void releaseTenant(String tenantId) {

        ThreadLifeCycleObserver observer = new ThreadLifeCycleObserver();

        // 线程异步处理
        new Thread(new ObservableRunnable(observer, () -> {

            saveCommonAnnouncementIssueInfo(tenantId);

        })).start();
    }

    public void saveCommonAnnouncementIssueInfo(String tenantId) {
        // 查出默认新闻
        Wrapper<CommonAnnouncementIssueInfo> wrapper = new EntityWrapper<CommonAnnouncementIssueInfo>();
        wrapper.ne(CommonAnnouncementIssueInfo.QueryFields.DEFAULT_NEWS, "0");
        wrapper.isNotNull(CommonAnnouncementIssueInfo.QueryFields.DEFAULT_NEWS);
        wrapper.orderBy(CommonAnnouncementIssueInfo.QueryFields.DEFAULT_NEWS, false);
        List<CommonAnnouncementIssueInfo> commonInfoList = announcementIssueInfoMapper.selectList(wrapper);

        if (CollectionUtils.isEmpty(commonInfoList)) {
            return;
        }

        List<AnnoIssueInfo> issueInfoList = new ArrayList<>();
        List<AnnoReadUserInfo> readUserInfoList = new ArrayList<>();
        List<CommonCompany> companyList = companyService.selectList(new EntityWrapper<CommonCompany>()
                .eq(CommonCompany.QueryFields.TENANT_ID, tenantId));
        for (CommonAnnouncementIssueInfo info : commonInfoList) {
            // 如果当前新闻有封面需要给发送的公司复制一份
            CommonAppendix appendix = appendixService.selectById(info.getOssCoverUrl());

            companyList.forEach(company -> {
                // 创建新闻信息
                AnnoIssueInfo issueInfo = new AnnoIssueInfo();
                BeanUtils.copyProperties(info, issueInfo);
                issueInfo.setTenantId(tenantId);
                issueInfo.setTenantName(company.getCompName());
                issueInfo.setCompId(company.getCompId());
                issueInfo.setId(IdGenerator.generateUUID());
                issueInfo.setSystemFlag("1");
                issueInfo.setParentId(info.getId());
                if (issueInfoList.size() == 0) {
                    issueInfo.setIssueDate(new Date(System.currentTimeMillis() + 2 * 1000));// 第一条新闻延后一分钟 为了排在第一条
                } else {
                    issueInfo.setIssueDate(new Date());
                }

                // 给每个公司插一份附件信息
                if (appendix != null) {
                    appendix.setCompId(company.getCompId());
                    appendix.setAppendixId(IdGenerator.generateUUID());
                    appendixService.insert(appendix);
                    issueInfo.setOssCoverUrl(appendix.getAppendixId());
                }

                // 给当前公司所有部门插入新闻信息
                List<CommonDepartment> departmentList = departmentService.selectList(new EntityWrapper<CommonDepartment>()
                        .eq(CommonDepartment.QueryFields.COMP_ID, company.getCompId()));
                if (CollectionUtils.isNotEmpty(departmentList)) {
                    issueInfoList.add(issueInfo);
                    departmentList.forEach(e -> {
                        AnnoReadUserInfo annoReadUserInfo = new AnnoReadUserInfo();
                        annoReadUserInfo.setAnnouncementId(issueInfo.getId());
                        annoReadUserInfo.setCompId(issueInfo.getCompId());
                        annoReadUserInfo.setReadUserId(e.getDeptId());
                        annoReadUserInfo.setId(IdGenerator.generateUUID());
                        annoReadUserInfo.setIsRead("0");
                        readUserInfoList.add(annoReadUserInfo);
                    });
                }
            });
        }
        this.insertBatch(issueInfoList);
        readUserInfoService.insertBatch(readUserInfoList);
    }

    /**
     * 新闻-极光推送
     *
     * @param issueInfo
     * @param userInfo
     */
    @Override
    public void jpush(AnnoIssueInfo issueInfo, AnnoReadUserInfo userInfo) {
        String content = issueInfo.getContent();
        content = content.replaceAll("</?[^>]+>", "");
        content = content.replaceAll("<a>\\s*|\\t|\\r|\\n</a>", "");
        content = content.replaceAll("<.*?>", "");
        content = content.replaceAll("<.*?", "");
        content = content.replaceAll("\\n", "");
        content = content.replaceAll("\\r", "");
        content = content.replaceAll("\\t", "");
        content = content.replaceAll("&[^;]*;", "");
        content = content.replaceAll("/<[^>]+>/g", "");
        if (content.length() > 500) {
            content = content.substring(0, 500);
        }
        NotificationStaffTodoTask task = new NotificationStaffTodoTask();
        task.setMessageTitle(issueInfo.getTitle());
        task.setMessageContent(content);
        task.setStaffId(userInfo.getReadUserId());
        task.setBusinessId(issueInfo.getId());
        task.setBusinessCode("NEWS");
    }

}
