package com.gic.haoban.manage.service.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.gic.api.base.commons.BasePageInfo;
import com.gic.api.base.commons.Page;
import com.gic.api.base.commons.ServiceResponse;
import com.gic.clerk.api.dto.ClerkDTO;
import com.gic.clerk.api.service.ClerkService;
import com.gic.commons.util.PageHelperUtils;
import com.gic.commons.util.UniqueIdUtils;
import com.gic.enterprise.api.dto.EnterpriseUsingPermissionDto;
import com.gic.enterprise.api.dto.StoreDTO;
import com.gic.enterprise.api.dto.StoreSearchDTO;
import com.gic.enterprise.api.service.EnterpriseUseForbidService;
import com.gic.enterprise.api.service.StoreGroupService;
import com.gic.enterprise.api.service.StoreService;
import com.gic.haoban.manage.api.dto.OpenStaffListDTO;
import com.gic.haoban.manage.api.dto.StaffClerkRelationDTO;
import com.gic.haoban.manage.api.dto.StoreClerkDTO;
import com.gic.haoban.manage.api.enums.NoticeMessageTypeEnum;
import com.gic.haoban.manage.api.enums.OpenStaffOfflineEnum;
import com.gic.haoban.manage.api.qdto.OpenStaffPageQDTO;
import com.gic.haoban.manage.api.service.StaffApiService;
import com.gic.haoban.manage.api.service.notify.NoticeMessageApiService;
import com.gic.haoban.manage.api.util.notify.NoticeMessageUtil;
import com.gic.haoban.manage.service.dao.mapper.OpenStaffMapper;
import com.gic.haoban.manage.service.dao.mapper.StaffMapper;
import com.gic.haoban.manage.service.entity.TabHaobanStaff;
import com.gic.haoban.manage.service.entity.TabOpenStaff;
import com.gic.haoban.manage.service.pojo.QwOpenResultInitBO;
import com.gic.haoban.manage.service.service.OpenStaffService;
import com.gic.haoban.manage.service.service.StaffClerkRelationService;
import com.gic.haoban.manage.service.util.CustomSwitcher;
import com.gic.haoban.manage.service.util.OpenUtils;
import com.gic.redis.data.util.RedisUtil;
import com.github.pagehelper.PageHelper;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

@Service("openStaffService")
public class OpenStaffServiceImpl implements OpenStaffService {

    private static final Logger log = LogManager.getLogger(OpenStaffService.class);

    @Autowired
    private OpenStaffMapper openStaffMapper;
    @Autowired
    private StaffClerkRelationService staffClerkRelationService;
    @Autowired
    private StoreGroupService storeGroupService;
    @Autowired
    private StoreService storeService;
    @Autowired
    private ClerkService clerkService;
    @Autowired
    private NoticeMessageApiService noticeMessageApiService;
    @Autowired
    private StaffMapper staffMapper;
    @Autowired
    private EnterpriseUseForbidService enterpriseUseForbidService;
    @Autowired
    private StaffApiService staffApiService ;

    @Override
    public TabOpenStaff save(TabOpenStaff tab) {
        tab.setUpdateTime(new Date());
        if (null == tab.getOpenStaffId()) {
            tab.setOpenStaffId(UniqueIdUtils.uniqueLong());
            tab.setDeleteFlag(0);
            tab.setCreateTime(new Date());
            this.openStaffMapper.insert(tab);
        } else {
            this.openStaffMapper.update(tab);
        }
        return tab;
    }

    @Override
    public TabOpenStaff getByUUID(String uuid) {
        TabOpenStaff openStaff = this.openStaffMapper.getByUUID(uuid);
        if (null == openStaff) {
            log.info("通过uuid查不到={}", uuid);
            // OpenUtils.logout(uuid);
        }
        return openStaff;
    }

    @Override
    public void logout(String uuid, String loginRemark, int step, String noticeReason) {
        TabOpenStaff openStaff = this.getByUUID(uuid);
        if (null == openStaff) {
            return;
        }
        OpenUtils.logout(uuid);
        openStaff.setStep(step);
        openStaff.setStatusFlag(2);
        openStaff.setValidFlag(0);
        openStaff.setValidQrcodeFlag(0);
        openStaff.setQrCode1(null);
        openStaff.setQrCode2(null);
        openStaff.setKey1(null);
        openStaff.setKey2(null);
        openStaff.setUuid(uuid);
        openStaff.setLoginRemark(loginRemark);
        this.openStaffMapper.update(openStaff);

        // 发送通知
        if (StringUtils.isNotBlank(noticeReason)) {
            log.info("发送退出登录通知,staffId={}", openStaff.getStaffId());
            TabHaobanStaff staff = this.staffMapper.selectByPrimaryKey(openStaff.getStaffId());
            this.noticeMessageApiService.sendMessageForOpenStaff(openStaff.getEnterpriseId(), staff.getStaffName(), noticeReason);
            //  发送通知
            if(!noticeReason.equals(OpenStaffOfflineEnum.OFFLINE1.getDesc())) {
                Map<String, String> map = new HashMap<String, String>();
                map.put("reason", noticeReason);
                int messageType = NoticeMessageTypeEnum.HAOBAN_OPEN_STAFF_LOGOUT.getType();
                NoticeMessageUtil.sendNoticeMessageByStaff(openStaff.getEnterpriseId(), openStaff.getStaffId(), "-1", messageType, null, map, null);
            }
        }
    }

    @Override
    public ServiceResponse<Page<OpenStaffListDTO>> page(OpenStaffPageQDTO qdto, BasePageInfo basePageInfo) {
        log.info("分页查询条件={}", JSONObject.toJSONString(qdto));
        String wxEnterpriseId = qdto.getWxEnterpriseId();
        String enterpriseId = qdto.getEnterpriseId();
        List<String> storeIdList = staffApiService.getHaoBanStoreIdsRolesByClerkId(qdto.getLoginClerkId(), wxEnterpriseId);
        if(CollectionUtils.isEmpty(storeIdList)) {
            return ServiceResponse.success(new Page<>());
        }
        if (CollectionUtils.isNotEmpty(qdto.getStoreGroupIdList())) {
            storeIdList = this.getStoreIdList(enterpriseId, qdto.getStoreGroupIdList(),storeIdList);
        }
        if((storeIdList.size()==1 && storeIdList.contains("-1"))) {
            storeIdList = null ;
        }
        if (StringUtils.isNotBlank(qdto.getClerkId()) || CollectionUtils.isNotEmpty(storeIdList)) {
            List<String> staffIds = staffClerkRelationService.listAllStaffIdForOpenStaff(enterpriseId, wxEnterpriseId, qdto.getClerkId(), storeIdList);
            if (CollectionUtils.isEmpty(staffIds)) {
                return ServiceResponse.success(new Page<>());
            }
            qdto.setStaffIds(staffIds);
        }
        PageHelper.startPage(basePageInfo);
        List<OpenStaffListDTO> list = this.openStaffMapper.list(qdto);
        if (CollectionUtils.isEmpty(list)) {
            return ServiceResponse.success(new Page<>());
        }
        Set<String> staffIdList = list.stream().map(dto -> dto.getStaffId()).collect(Collectors.toSet());
        List<StaffClerkRelationDTO> relationDTOList = staffClerkRelationService.listByWxEnterpriseIdAndStaffId(wxEnterpriseId, staffIdList);
        relationDTOList = relationDTOList.stream().filter(o -> o.getEnterpriseId().equals(enterpriseId)).collect(Collectors.toList());
        Map<String, ClerkDTO> clerkMap = new HashMap<>();
        if (CollectionUtils.isNotEmpty(relationDTOList)) {
            Set<String> clerkIdSet = relationDTOList.stream().map(o -> o.getClerkId()).collect(Collectors.toSet());
            if (CollectionUtils.isNotEmpty(clerkIdSet)) {
                List<ClerkDTO> clerkDTOS = this.clerkService.getClerkByIds(clerkIdSet);
                clerkMap.putAll(clerkDTOS.stream().collect(Collectors.toMap(o -> o.getClerkId(), o -> o, (k1, k2) -> k1)));
            }
        }
        log.info("导购={}", JSONObject.toJSONString(clerkMap));
        for (OpenStaffListDTO item : list) {
            String staffId = item.getStaffId();
            List<StoreClerkDTO> clerkList = new ArrayList<>();
            for (StaffClerkRelationDTO clerkRelation : relationDTOList) {
                if (clerkRelation.getStaffId().equals(staffId)) {
                    String storeId = clerkRelation.getStoreId();
                    String clerkId = clerkRelation.getClerkId();
                    ClerkDTO clerkDTO = clerkMap.get(clerkId);
                    if (null != clerkDTO) {
                        StoreClerkDTO cs = new StoreClerkDTO();
                        cs.setClerkId(clerkId);
                        cs.setClerkName(clerkDTO.getClerkName());
                        cs.setClerkCode(clerkDTO.getClerkCode());
                        StoreDTO store = this.storeService.getStore(storeId);
                        if (null != store) {
                            cs.setStoreId(storeId);
                            cs.setStoreName(store.getStoreName());
                            cs.setStoreCode(store.getStoreCode());
                        }
                        clerkList.add(cs);
                    }
                }
            }
            item.setClerkList(clerkList);
        }
        Page<OpenStaffListDTO> retPage = PageHelperUtils.changePageHelperToCurrentPage(list, OpenStaffListDTO.class);
        log.info("分页查询结果={}", JSONObject.toJSONString(retPage, true));
        return ServiceResponse.success(retPage);
    }

    @Override
    public List<String> listAllStaffId(String wxEnterpriseId) {
        return this.openStaffMapper.listAllStaffId(wxEnterpriseId);
    }


    private List<String> getStoreIdList(String enterpriseId, List<String> storeGroupIds , List<String> storeList) {
        StoreSearchDTO storeSearch = new StoreSearchDTO();
        List<String> groupIds = storeGroupService.getStoreGroupIdsByParentGroupId(enterpriseId, storeGroupIds);
        storeSearch.setStoreGroupIdList(groupIds);
        storeSearch.setEnterpriseId(enterpriseId);
        storeSearch.setStatus("2");
        Page pageStore = new Page<>();
        //-1代表不分页
        pageStore.setCurrentPage(-1);
        if(!(storeList.size()==1 && storeList.contains("-1"))) {
            storeSearch.setStoreIdList(storeList);
        }
        Page resultPage = storeService.storeListPage(pageStore, storeSearch);
        List<StoreDTO> storeDTOList = resultPage.getResult();
        if (CollectionUtils.isEmpty(storeDTOList)) {
            return new ArrayList<>();
        }
        log.info("门店条件查询,返回={}条", storeDTOList.size());
        List<String> searchStoreIds = storeDTOList.stream().map(StoreDTO::getStoreId).distinct().collect(Collectors.toList());
        return searchStoreIds;
    }

    @Override
    public String autoLogin(Long openStaffId, Long qwUserId , String wxEnterpriseId) {
        ServiceResponse<QwOpenResultInitBO> initResp = OpenUtils.init(qwUserId, false ,this.getDeverType(wxEnterpriseId));
        log.info("自动登录-初始化={},{}", qwUserId, JSONObject.toJSONString(initResp));
        if (initResp.isSuccess() && StringUtils.isNotBlank(initResp.getResult().getUuid())) {
            QwOpenResultInitBO bo = initResp.getResult();
            String newUuid = bo.getUuid();
            if (bo.isIs_login()) {
                this.openStaffMapper.updateByAutoLogin(openStaffId, newUuid);
                return newUuid;
            }
            boolean autLogin = OpenUtils.autoLogin(newUuid);
            if (autLogin) {
                this.openStaffMapper.updateByAutoLogin(openStaffId, newUuid);
                return newUuid;
            }
        }
        return null;
    }

    /**
     * 1. 首次登录流程
     * 初始化 扫码登录
     * <p>
     * 2. 自动重连流程
     * 如果登录了很多号，我结束服务，重启服务后
     * 初始化接口 vid传登陆过的账号userid 然后 初始化接口返回有个is_login=true 代表连上了如果是false就走自动登录接口
     * 如果自动登录失败，获取二维码扫码登录
     * <p>
     * 3. 自动登录
     * 如果一个号登录了，调用了退出接口，下次初始化接口vid填这个号的id然后调用自动登录接口，登录失败 走扫码
     */
    @Override
    public void openStaffTimer() {
        log.info("定时检查托管状态");
        Object o = RedisUtil.getCache("haobansilk2mp3") ;
        if(null == o) {
            com.gic.haoban.common.utils.DingUtils.send("请检查silk2mp3", false);
        }
        List<TabOpenStaff> list = this.openStaffMapper.listAllOnline(null, null);
        for (TabOpenStaff item : list) {
            try{
                String uuid = item.getUuid();
                boolean isLogin = OpenUtils.isLogin(uuid);
                // 未登录
                if (!isLogin) {
                    String autLogin = this.autoLogin(item.getOpenStaffId(), item.getQwUserId(), item.getWxEnterpriseId());
                    if (null == autLogin) {
                        this.logout(uuid, "定时检查异", 0, OpenStaffOfflineEnum.OFFLINE2.getDesc());
                    }
                }
            }catch (Exception e) {
                log.info("异常",e);
            }
        }
    }

    @Override
    public void openStaffServiceTimer() {
        log.info("托管服务到期");
        List<TabOpenStaff> list = this.openStaffMapper.listAllOnlineEnterprise();
        if(CollectionUtils.isNotEmpty(list)) {
            for (TabOpenStaff item : list) {
                String wxEnterpriseId = item.getWxEnterpriseId() ;
                String enterpriseId = item.getEnterpriseId() ;
                boolean isValid = this.isValid(wxEnterpriseId,enterpriseId) ;
                log.info("是否有效={},{},{}",isValid,wxEnterpriseId,enterpriseId);
                if (!isValid) {
                    List<TabOpenStaff> staffList = this.openStaffMapper.listAllOnline(wxEnterpriseId, enterpriseId);
                    if(CollectionUtils.isNotEmpty(staffList)) {
                        staffList.forEach(o->{
                            try {
                                this.logout(o.getUuid(), "服务过期", 0, null);
                            }catch (Exception e) {
                                log.info("异常",e);
                            }
                        });
                    }
                }
            }
        }
    }

    private boolean isValid(String wxEnterpriseId, String enterpriseId) {
        ServiceResponse<EnterpriseUsingPermissionDto> resp = this.enterpriseUseForbidService.getWxEnterpriseService(enterpriseId, wxEnterpriseId);
        log.info("托管许可={}", JSONObject.toJSONString(resp));
        if (resp.isSuccess()) {
            EnterpriseUsingPermissionDto dto = resp.getResult();
            if (null == dto) {
                return false ;
            } else {
                if (dto.getServiceEndDate().before(new Date())) {
                    return false ;
                }
            }
        }
        return true ;
    }


    @Override
    public String getDeverType(String wxEnterpriseId) {
        if(StringUtils.isBlank(wxEnterpriseId)) {
            return null ;
        }
        return CustomSwitcher.qywx_open_type.get(wxEnterpriseId) ;
    }
}
