package com.fjhx.victoriatourist.service.logistics.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.area.utils.CustomizeAreaUtil;
import com.fjhx.common.constant.SourceConstant;
import com.fjhx.common.utils.Assert;
import com.fjhx.kd100.entity.company.po.CompanyInfo;
import com.fjhx.kd100.entity.config.po.ConfigInfo;
import com.fjhx.kd100.entity.logistics.po.LogisticsInfo;
import com.fjhx.kd100.event.Kd100CallbackEvent;
import com.fjhx.kd100.service.company.CompanyInfoService;
import com.fjhx.kd100.service.config.ConfigInfoService;
import com.fjhx.kd100.util.KD100Result;
import com.fjhx.kd100.util.KD100Util;
import com.fjhx.purchase.entity.purchase.po.Purchase;
import com.fjhx.purchase.service.purchase.PurchaseService;
import com.fjhx.victoriatourist.entity.logistics.dto.LogisticsInfosDto;
import com.fjhx.victoriatourist.entity.logistics.dto.LogisticsInfosSelectDto;
import com.fjhx.victoriatourist.entity.logistics.po.LogisticsDetails;
import com.fjhx.victoriatourist.entity.logistics.po.LogisticsInfos;
import com.fjhx.victoriatourist.entity.logistics.vo.LogisticsInfosVo;
import com.fjhx.victoriatourist.mapper.logistics.LogisticsInfosMapper;
import com.fjhx.victoriatourist.service.jd.JdBackService;
import com.fjhx.victoriatourist.service.logistics.LogisticsDetailsService;
import com.fjhx.victoriatourist.service.logistics.LogisticsInfosService;
import com.fjhx.victoriatourist.utils.LogisticsConstant;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.wrapper.IWrapper;
import com.ruoyi.framework.mybatis.holder.TenantHolder;
import com.ruoyi.system.service.ISysRoleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;


/**
 * <p>
 * 物流信息 服务实现类
 * </p>
 *
 * @author
 * @since 2023-04-17
 */
@Slf4j
@Service
public class LogisticsInfosServiceImpl extends ServiceImpl<LogisticsInfosMapper, LogisticsInfos> implements LogisticsInfosService {
    @Autowired
    private CompanyInfoService companyInfoService;
    @Autowired
    private LogisticsDetailsService logisticsDetailsService;
    @Autowired
    private PurchaseService purchaseService;
    @Autowired
    private JdBackService jdBackService;
    @Autowired
    private ISysRoleService sysRoleService;
    @Autowired
    private ConfigInfoService configInfoService;


    @Override
    public Page<LogisticsInfosVo> getPage(LogisticsInfosSelectDto dto) {
        IWrapper<LogisticsInfos> wrapper = getWrapper();
        wrapper.eq("li", LogisticsInfos::getId, dto.getId());

        wrapper.eq("li", LogisticsInfos::getBusinessType, dto.getBusinessType());
        wrapper.eq("li", LogisticsInfos::getLogisticsStatus, dto.getLogisticsStatus());
        wrapper.eq("li", LogisticsInfos::getStatus, dto.getStatus());
        if (ObjectUtil.isNotEmpty(dto.getKeyword())) {
            List<String> companyCodes = companyInfoService.listObject(CompanyInfo::getCode, q -> q.like(CompanyInfo::getName, dto.getKeyword()));
            wrapper.and(q -> q.like("li", LogisticsInfos::getCode, dto.getKeyword())
                    .or().like("li", LogisticsInfos::getBusinessCode, dto.getKeyword())
                    .or().in("li", LogisticsInfos::getLogisticsCompanyCode, companyCodes)
                    .or().like("pi.custom_code", dto.getKeyword())
                    .or().like("pi.name", dto.getKeyword())
            );
        }

        //添加权限过滤
        DynamicDataSourceContextHolder.push(SourceConstant.BASE);
        Set<String> permissionList = sysRoleService.selectRolePermissionByUserId(SecurityUtils.getUserId());
        DynamicDataSourceContextHolder.poll();
        if (ObjectUtil.isNotEmpty(permissionList)) {
            //if当前用户的角色 in [运营专员, 运营助理] 页面仅展示产品.管理部门 == 当前用户所在部门或下级部门的相关数据
            if (permissionList.contains("E-commerce operation") || permissionList.contains("Operation assistant")) {
                wrapper.and(q -> q.eq("de.dept_id", SecurityUtils.getDeptId())
                        .or()
                        .like("de.ancestors", SecurityUtils.getDeptId()));
            }
        }

        //部门(项目组)过滤
        wrapper.eq("de.dept_id", dto.getDeptId());

        wrapper.groupBy("li.id");

        wrapper.orderByDesc("li", LogisticsInfos::getId);
        Assert.notEmpty(dto.getBusinessType(), "物流数据来源类型不能为空");
        Page<LogisticsInfosVo> page = this.baseMapper.getPage(dto.getPage(), wrapper, dto.getBusinessType());
        List<LogisticsInfosVo> records = page.getRecords();
        //赋值物流公司名字
        List<String> codes = records.stream().map(LogisticsInfosVo::getLogisticsCompanyCode).collect(Collectors.toList());
        if (ObjectUtil.isEmpty(codes)) {
            return page;
        }
        List<CompanyInfo> list = companyInfoService.list(q -> q.in(CompanyInfo::getCode, codes));
        if (ObjectUtil.isNotEmpty(list)) {
            Map<String, String> companyMap = list.stream().collect(Collectors.toMap(CompanyInfo::getCode, CompanyInfo::getName));
            for (LogisticsInfosVo record : records) {
                String name = companyMap.get(record.getLogisticsCompanyCode());
                record.setLogisticsCompanyName(name);
            }
        }
        //赋值国省市名称
        CustomizeAreaUtil.setAreaName(records);
        return page;
    }

    @Override
    public LogisticsInfosVo detail(Long id) {
        LogisticsInfos LogisticsInfos = this.getById(id);
        LogisticsInfosVo result = BeanUtil.toBean(LogisticsInfos, LogisticsInfosVo.class);
        //赋值国省市名称
        CustomizeAreaUtil.setAreaName(Collections.singletonList(result));
        return result;
    }

    @DSTransactional
    @Override
    public void add(LogisticsInfosDto logisticsInfosDto) {
        long logisticsInfosId = IdWorker.getId();
        logisticsInfosDto.setId(logisticsInfosId);
        if (logisticsInfosDto.getIsKd100() == 1) {
            //发起快递100订阅
            DynamicDataSourceContextHolder.push(SourceConstant.KD100);
            Integer state = KD100Util.monitor(logisticsInfosDto.getLogisticsCompanyCode(), logisticsInfosDto.getCode(), logisticsInfosId, 1, LogisticsInfos.class).getState();
            logisticsInfosDto.setLogisticsStatus(state);
            logisticsInfosDto.setIsKd100(1);
            DynamicDataSourceContextHolder.poll();
        }
        this.save(logisticsInfosDto);
        LogisticsDetails logisticsDetails = new LogisticsDetails();
        logisticsDetails.setLogisticsInfoId(logisticsInfosDto.getId());
        logisticsDetails.setRemark(logisticsInfosDto.getRemark());
        logisticsDetailsService.save(logisticsDetails);
    }

    @DSTransactional
    @EventListener
    public void kd100EventListener(Kd100CallbackEvent event) {
        LogisticsInfo logisticsInfo = event.getLogisticsInfo();
        //监听物流状态变化
        if (KD100Util.getTableName(LogisticsInfos.class).equals(logisticsInfo.getTableName())) {
            DynamicDataSourceContextHolder.push(SourceConstant.VICTORIATOURIST);
            LogisticsInfos byId = this.getById(logisticsInfo.getBusinessId());
            DynamicDataSourceContextHolder.poll();
            if (ObjectUtil.notEqual(logisticsInfo.getState(), byId.getLogisticsStatus())) {
                byId.setLogisticsStatus(logisticsInfo.getState());
                DynamicDataSourceContextHolder.push(SourceConstant.VICTORIATOURIST);
                this.updateById(byId);
                DynamicDataSourceContextHolder.poll();
                //如果是京东退货且物流状态为完成
                jdBackService.updateJdBack(byId);
            }
        }
    }

    @Override
    public void edit(LogisticsInfosDto logisticsInfosDto) {
        if (logisticsInfosDto.getIsKd100() == 1) {
            //发起快递100订阅
            DynamicDataSourceContextHolder.push(SourceConstant.KD100);
            Integer state = KD100Util.monitor(logisticsInfosDto.getLogisticsCompanyCode(), logisticsInfosDto.getCode(), logisticsInfosDto.getId(), logisticsInfosDto.getBusinessType(), LogisticsInfos.class).getState();
            logisticsInfosDto.setLogisticsStatus(state);
            logisticsInfosDto.setIsKd100(1);
            DynamicDataSourceContextHolder.poll();
        }

        this.updateById(logisticsInfosDto);
    }

    @Override
    public void delete(Long id) {
        this.removeById(id);
    }

    @Override
    public KD100Result getLogistics(Long id) {
        LogisticsInfos logisticsInfo = this.getById(id);
        Assert.notEmpty(logisticsInfo, "没有找到物流信息");
        return KD100Util.queryTrack(logisticsInfo.getLogisticsCompanyCode(), logisticsInfo.getCode());
    }

    @Override
    @DSTransactional
    public void dataInfoEdit(Long id) {
        LogisticsInfos logisticsInfo = getById(id);
        Assert.notEmpty(logisticsInfo, "没有找到物流信息");
        KD100Result kd100Result = KD100Util.queryTrack(logisticsInfo.getLogisticsCompanyCode(), logisticsInfo.getCode());
        Integer state = kd100Result.getState();
        if (ObjectUtil.notEqual(state, logisticsInfo.getLogisticsStatus())) {
            //原来是异常物流信息 限制刷新到状态就添加订阅
            if (logisticsInfo.getLogisticsStatus() == -1) {
                KD100Util.subscribe(logisticsInfo.getLogisticsCompanyCode(), logisticsInfo.getCode());
            }
            logisticsInfo.setLogisticsStatus(state);
            updateById(logisticsInfo);
            //如果是京东退货且物流状态为完成
            jdBackService.updateJdBack(logisticsInfo);
        }
    }

    @Override
    public void arrivalNotice(LogisticsInfosVo entity) {
        // 采购id
        Long purchaseId = entity.getPurchaseId();
        Assert.notEmpty(purchaseId, "采购id不能为空");

        entity.setStatus(LogisticsConstant.Status.STATUS_1);
        updateById(entity);

        Purchase purchase = new Purchase();
        purchase.setId(purchaseId);
        purchase.setArrivalStatus(10);//设置部分到货
        purchaseService.updateById(purchase);

        //物流到货通知
        Assert.notEmpty(entity.getId(), "物流id不能为空");
        LogisticsInfos logisticsInfo = new LogisticsInfos();
        logisticsInfo.setId(entity.getId());
        logisticsInfo.setLogisticsStatus(15);
        updateById(logisticsInfo);
    }

    /**
     * 获取物流关联产品部门列表
     */
    @Override
    public List<SysDept> getDepts() {
        return baseMapper.getDepts();
    }

    /**
     * 每天0点刷新近3天的异常物流信息
     * "0 0/1 * * * ?"
     */
    @Scheduled(cron = "0 0 0 * * ?")
    void updateLast3DayInfo() {
        String tenantId = "wdly";
        TenantHolder.setIgnore(true);
        ConfigInfo configInfo = configInfoService.getOne(q -> q.eq(ConfigInfo::getTenantId, tenantId));
        if (configInfo == null) {
            return;
        }
        DynamicDataSourceContextHolder.push(SourceConstant.VICTORIATOURIST);
        IWrapper<LogisticsInfos> wrapper = IWrapper.getWrapper();
        wrapper.eq(LogisticsInfos::getLogisticsStatus, -1);
        wrapper.eq(LogisticsInfos::getIsKd100, 1);
        wrapper.eq("tenant_id", tenantId);
        wrapper.apply("DATE_SUB( CURDATE(), INTERVAL 3 DAY )<= create_time");
        List<LogisticsInfos> list = this.list(wrapper);
        if (ObjectUtil.isEmpty(list)) {
            return;
        }
        for (LogisticsInfos logisticsInfos : list) {
            String com = logisticsInfos.getLogisticsCompanyCode();
            String num = logisticsInfos.getCode();
            try {
                KD100Result kd100Result = KD100Util.queryTrack(com, num, configInfo);
                if (kd100Result.getState() == null || kd100Result.getState() == -1) {
                    continue;
                }
                logisticsInfos.setLogisticsStatus(kd100Result.getState());
                //重新订阅
                KD100Util.subscribe(com, num, configInfo);
                Thread.sleep(2000);
            } catch (Exception e) {
                log.error("重新同步异常物流信息出错： com:{}, num:{}, message:{}", com, num, e.getMessage(), e);
            }
        }
        this.updateBatchById(list);
        DynamicDataSourceContextHolder.clear();
        TenantHolder.clear();
    }

}
