package com.fjhx.customer.service.customer.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
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.entity.coding.bo.CustomerCodeAndCountryId;
import com.fjhx.common.service.coding.CodingRuleCustomerService;
import com.fjhx.customer.entity.customer.dto.CustomerDto;
import com.fjhx.customer.entity.customer.dto.CustomerSelectDto;
import com.fjhx.customer.entity.customer.po.Customer;
import com.fjhx.customer.entity.customer.po.CustomerTop;
import com.fjhx.customer.entity.customer.po.CustomerUser;
import com.fjhx.customer.entity.customer.vo.CustomerFollowRecordsVo;
import com.fjhx.customer.entity.customer.vo.CustomerVo;
import com.fjhx.customer.mapper.customer.CustomerMapper;
import com.fjhx.customer.service.customer.CustomerService;
import com.fjhx.customer.service.customer.CustomerTopService;
import com.fjhx.customer.service.customer.CustomerUserService;
import com.fjhx.customer.utils.code.CodeEnum;
import com.fjhx.tenant.entity.dict.dto.DictTenantDataSelectDto;
import com.fjhx.tenant.entity.dict.vo.DictTenantDataVo;
import com.fjhx.tenant.service.dict.DictTenantDataService;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.wrapper.IWrapper;
import com.ruoyi.system.utils.UserUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * <p>
 * 客户表 服务实现类
 * </p>
 *
 * @author
 * @since 2023-04-04
 */
@Service
public class CustomerServiceImpl extends ServiceImpl<CustomerMapper, Customer> implements CustomerService, CodingRuleCustomerService {

    @Autowired
    private CustomerUserService customerUserService;

    @Autowired
    private CustomerTopService customerTopService;

    @Autowired
    private DictTenantDataService dictTenantDataService;


    /**
     * 客户下拉分页
     */
    @Override
    public Page<CustomerVo> selPage(CustomerSelectDto dto) {
        IWrapper<CustomerVo> wrapper = IWrapper.getWrapper();
        wrapper.like(Customer::getName, dto.getKeyword());

        SysUser sysUser = UserUtil.getUserInfo();
        //不是业务员看所有私海客户
        wrapper.isNotNull("c.user_id");
        //是业务员只能看自己的客户(如果业务员是部门负责人/部门总监可以看本部门以及下级部门的客户)
        if (StringUtils.isNotEmpty(sysUser.getUserCode())) {
            List<Long> authIdList = this.getAuthIdList();
            if (authIdList.size() == 0) {
                return new Page<>();
            }
            wrapper.in("c", Customer::getId, authIdList);
        }

        //最后跟进数据过滤
        Integer beginDay = dto.getBeginDay();
        Integer endDay = dto.getEndDay();
        wrapper.and(ObjectUtil.isNotEmpty(beginDay), q -> q
                .gt("DATEDIFF( NOW(), c.last_follow_time )", beginDay)
                .or().isNull(ObjectUtil.isEmpty(endDay), "c.last_follow_time")
        );
        wrapper.le(ObjectUtil.isNotEmpty(endDay), "DATEDIFF( NOW(), c.last_follow_time )", endDay);

        Page<CustomerVo> page = baseMapper.getPage(dto.getPage(), wrapper);
        CustomizeAreaUtil.setAreaName(page.getRecords());
        return page;
    }

    /**
     * 查询客户的列表
     *
     * @param dto
     * @return
     */
    @Override
    public Page<CustomerVo> getPage(CustomerSelectDto dto) {

        IWrapper<CustomerVo> wrapper = IWrapper.getWrapper();

        // 客户来源查询
        wrapper.eq("c", Customer::getSource, dto.getSource());
        // 客户类型查询
        wrapper.eq("c", Customer::getStatus, dto.getStatus());
        // 国家ID查询
        wrapper.eq("c", Customer::getCountryId, dto.getCountryId());
        // 省份ID查询
        wrapper.eq("c", Customer::getProvinceId, dto.getProvinceId());
        // 城市ID查询
        wrapper.eq("c", Customer::getCityId, dto.getCityId());
        // 客户代码
        wrapper.like("c", Customer::getCustomerCode, dto.getCustomerCode());
        // 客户名称
        wrapper.like("c", Customer::getName, dto.getName());
        // 业务员查询
        wrapper.eq("c", Customer::getUserId, dto.getUserId());
        // 关键字
        if (ObjectUtil.isNotEmpty(dto.getKeyword())) {
            List<Long> cuIds = customerUserService.listObject(CustomerUser::getCustomerId, q -> q
                    .and(q1 -> q1
                            .like(CustomerUser::getName, dto.getKeyword()).or()
                            .like(CustomerUser::getEmail, dto.getKeyword())
                    )
                    .isNotNull(CustomerUser::getCustomerId)
                    .groupBy(CustomerUser::getCustomerId)
            );
            wrapper.and(q -> q
                    .like("c", Customer::getName, dto.getKeyword()).or()
                    .like(Customer::getCode, dto.getKeyword()).or()
                    .in(Customer::getId, cuIds)
            );
        }
        //客户联系人过滤
        if (ObjectUtil.isNotEmpty(dto.getContactName())) {
            List<Long> cuIds = customerUserService.listObject(CustomerUser::getCustomerId, q -> q
                    .like(CustomerUser::getName, dto.getContactName())
                    .isNotNull(CustomerUser::getCustomerId)
                    .groupBy(CustomerUser::getCustomerId)
            );
            cuIds.add(null);
            wrapper.in("c", Customer::getId, cuIds);
        }
        //客户联系人邮箱
        if (ObjectUtil.isNotEmpty(dto.getContactEmail())) {
            List<Long> cuIds = customerUserService.listObject(CustomerUser::getCustomerId, q -> q
                    .like(CustomerUser::getEmail, dto.getContactEmail())
                    .isNotNull(CustomerUser::getCustomerId)
                    .groupBy(CustomerUser::getCustomerId)
            );
            cuIds.add(null);
            wrapper.in("c", Customer::getId, cuIds);
        }

        // 客户标签查询（多个标签用逗号隔开）
        if (StrUtil.isNotBlank(dto.getTag())) {
            List<String> tagList = Arrays.asList(dto.getTag().split(","));
            tagList.forEach(tag -> wrapper.like("c", Customer::getTag, tag));
        }

        // 客户状态（0：公海客户  1：私海客户）(业务员ID为null为公海客户，业务员ID不为null为私海客户)
        if (StrUtil.isNotBlank(dto.getType())) {
            // 私海客户查询
            if (dto.getType().equals("1")) {
                wrapper.isNotNull("c.user_id");
            } else if (dto.getType().equals("0")) {
                wrapper.isNull("c.user_id");
            }
        }

        // 置顶条件
        List<Long> customerIds = customerTopService.listObject(CustomerTop::getCustomerId,
                q -> q.eq(CustomerTop::getUserId, SecurityUtils.getUserId()));

        if (ObjectUtil.isNotEmpty(customerIds)) {
            String join = StringUtils.join(customerIds, ",");
            wrapper.orderByDesc("c.id IN ( " + join + " )");
        }

        //最后跟进数据过滤
        Integer beginDay = dto.getBeginDay();
        Integer endDay = dto.getEndDay();
        wrapper.and(ObjectUtil.isNotEmpty(beginDay), q -> q
                .gt("DATEDIFF( NOW(), c.last_follow_time )", beginDay)
                .or().isNull(ObjectUtil.isEmpty(endDay), "c.last_follow_time")
        );
        wrapper.le(ObjectUtil.isNotEmpty(endDay), "DATEDIFF( NOW(), c.last_follow_time )", endDay);

        wrapper.orderByDesc("c", Customer::getAllocationTime);
        wrapper.orderByDesc("c", Customer::getCreateTime);

        Page<CustomerVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);

        // 复制城市信息
        List<CustomerVo> records = page.getRecords();
        CustomizeAreaUtil.setAreaName(records);

        //获取客户类型字典
        DynamicDataSourceContextHolder.push(SourceConstant.BASE);
        DictTenantDataSelectDto dictTenantDataSelectDto = new DictTenantDataSelectDto();
        dictTenantDataSelectDto.setDictCode("customer_status");
        List<DictTenantDataVo> dictTenantDataVoList = dictTenantDataService.getList(dictTenantDataSelectDto);
        Map<String, String> customerStatusDic = dictTenantDataVoList.stream().collect(Collectors.toMap(DictTenantDataVo::getDictKey, DictTenantDataVo::getDictValue));
        DynamicDataSourceContextHolder.poll();

        // 赋值客户跟进记录
        for (CustomerVo record : records) {
            List<CustomerFollowRecordsVo> followUp = baseMapper.getFollowUp(record.getId(), SecurityUtils.getTenantId());
            //赋值跟进人名称
            UserUtil.assignmentNickName(followUp, CustomerFollowRecordsVo::getCreateUser, CustomerFollowRecordsVo::setFollowUpUserName);
            record.setCustomerFollowRecordsList(followUp);

            //赋值客户状态字典值
            record.setStatusVal(customerStatusDic.get(record.getStatus()));
        }

        // 赋值是否置顶
        for (CustomerVo record : records) {
            record.setIsTop(customerIds.contains(record.getId()) ? 1 : 0);
        }

        return page;
    }

    /**
     * 查询客户的详情
     *
     * @param id
     * @return
     */
    @Override
    public CustomerVo detail(Long id) {
        //查询客户表的信息
        Customer Customer = this.getById(id);
        CustomerVo result = BeanUtil.toBean(Customer, CustomerVo.class);
        if (ObjectUtil.isEmpty(result)) {
            throw new ServiceException("没有找到该用户信息");
        }
        //查询客户-联系人表的信息
        List<CustomerUser> customerUserList = customerUserService.list(Wrappers.<CustomerUser>lambdaQuery()
                .eq(CustomerUser::getCustomerId, result.getId()));
        result.setCustomerUserList(customerUserList);
        CustomizeAreaUtil.setAreaName(result);
        return result;
    }

    /**
     * 添加客户表的数据
     *
     * @param customerDto
     */
    @Override
    @DSTransactional
    public void add(CustomerDto customerDto) {
        //赋值业务员分配时间
        if (ObjectUtil.isNotEmpty(customerDto.getUserId())) {
            customerDto.setAllocationTime(new Date());
        }

        //客户名称 唯一检查
        Customer repeatCustomer = this.getOne(q -> q.eq(Customer::getName, customerDto.getName()));
        if (ObjectUtil.isNotEmpty(repeatCustomer)) {
            Map<Long, String> nickNameMapByIds = UserUtil.getNickNameMapByIds(Collections.singletonList(repeatCustomer.getUserId()));
            String userName = nickNameMapByIds.get(repeatCustomer.getUserId());
            throw new ServiceException("添加失败。该客户名称已存在，绑定的业务员为" + userName);
        }

        CustomizeAreaUtil.setAreaId(customerDto);

        customerDto.setCode(CodeEnum.CUSTOMER.getCode());
        this.save(customerDto);
        //添加库户-联系人表的信息
        saveCustomerUse(customerDto);
    }

    /**
     * 修改客户表的数据
     *
     * @param customerDto
     */
    @DSTransactional
    @Override
    public void edit(CustomerDto customerDto) {
        //客户名称 唯一检查
        Customer repeatCustomer = this.getOne(q -> q.eq(Customer::getName, customerDto.getName()).ne(Customer::getId, customerDto.getId()));
        if (ObjectUtil.isNotEmpty(repeatCustomer)) {
            Map<Long, String> nickNameMapByIds = UserUtil.getNickNameMapByIds(Collections.singletonList(repeatCustomer.getUserId()));
            String userName = nickNameMapByIds.get(repeatCustomer.getUserId());
            throw new ServiceException("修改失败。该客户名称已存在，绑定的业务员为" + userName);
        }

        CustomizeAreaUtil.setAreaId(customerDto);

        // 修改客户表的信息
        this.updateById(customerDto);
        // 删除客户-用户表的信息
        customerUserService.remove(Wrappers.<CustomerUser>lambdaQuery().eq(CustomerUser::getCustomerId, customerDto.getId()));
        // 添加客户-联系人表的信息
        saveCustomerUse(customerDto);
    }

    /**
     * 删除客户表的数据
     *
     * @param
     */
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void delete(Long id) {
        //删除客户表的数据
        this.removeById(id);
        //删除客户-联系人表的数据
        customerUserService.remove(Wrappers.<CustomerUser>lambdaQuery().eq(CustomerUser::getCustomerId, id));
    }

    /**
     * 来源存量（客户分析）
     *
     * @param query
     * @return
     */
    @Override
    public List<CustomerVo> sourceStock(QueryWrapper<Object> query) {
        return baseMapper.sourceStock(query);
    }

    /**
     * 来源增量（客户分析）
     *
     * @param query
     * @return
     */
    @Override
    public List<CustomerVo> sourceIncrement(QueryWrapper<Object> query) {
        return baseMapper.sourceIncrement(query);
    }


    //添加客户用户表的信息
    private void saveCustomerUse(CustomerDto customerDto) {
        List<CustomerUser> customerUserDtoList = customerDto.getCustomerUserList();
        customerUserDtoList.forEach(customerUserDto -> customerUserDto.setCustomerId(customerDto.getId()));
        customerUserDtoList.forEach(customerUserDto -> customerUserDto.setId(null));//防止传id过来导致key冲突
        customerUserService.saveBatch(customerUserDtoList);
    }

    /**
     * 修改客户标签
     */
    @Override
    public void editTag(CustomerDto customerDto) {
        this.updateById(customerDto);
    }

    /**
     * 客户来源统计
     */
    @Override
    public Map<String, Object> sourceStatistics(CustomerSelectDto customerDto) {
        if (ObjectUtil.isEmpty(customerDto) && ObjectUtil.isEmpty(customerDto.getStatisticsType())) {
            throw new ServiceException("参数异常：统计类型不能为null");
        }
        //存放统计数据
        Map<String, Object> map = new HashMap<>();
        QueryWrapper<Customer> query = Wrappers.query();
        if (ObjectUtil.isNotEmpty(customerDto.getType())) {
            // 私海客户查询
            if (customerDto.getType().equals("1")) {
                query.isNotNull("user_id");
                // 私海客户需要添加权限（自己查自己）
                query.eq("user_id", SecurityUtils.getUserId());
            } else if (customerDto.getType().equals("0")) {// 公海客户
                query.and(wrapper1 -> wrapper1.isNull("user_id").or().eq("user_id", ""));
            }
        }
        if (customerDto.getStatisticsType() == 1) {// 来源统计
            query.groupBy("source");
            query.select("count(*) count,source");
        } else if (customerDto.getStatisticsType() == 2) {// 数据类型统计
            query.groupBy("status");
            query.select("count(*) count,status");
        } else if (customerDto.getStatisticsType() == 3) {// 业务员统计
            query.groupBy("user_id");
            query.select("count(*) count,user_id");
        }
        List<Customer> customerList = baseMapper.selectList(query);

        UserUtil.assignmentNickName(customerList, Customer::getUserId, Customer::setUserName);

        Integer countAmount = customerList.stream().map(Customer::getCount).reduce(Integer::sum).orElse(0);
        map.put("countAmount", countAmount);
        map.put("customerList", customerList);
        return map;
    }

    @Override
    public Map<String, Object> followStatistics(CustomerSelectDto customerDto) {
        if (ObjectUtil.isEmpty(customerDto) && ObjectUtil.isEmpty(customerDto.getStatisticsType())) {
            throw new ServiceException("参数异常：统计类型不能为null");
        }
        QueryWrapper<Customer> query = Wrappers.query();
        if (ObjectUtil.isNotEmpty(customerDto.getType())) {
            // 私海客户查询
            if (customerDto.getType().equals("1")) {
                query.isNotNull("user_id");
                // 私海客户需要添加权限（自己查自己）
                query.eq("user_id", SecurityUtils.getUserId());
            } else if (customerDto.getType().equals("0")) {// 公海客户
                query.and(wrapper1 -> wrapper1.isNull("user_id").or().eq("user_id", ""));
            }
        }

        // 客户最后一次跟进时间范围计数
        QueryWrapper<Customer> clone0 = query.clone();
        clone0.select("count(1) as count");
        clone0.gt("DATEDIFF( NOW(), last_follow_time )", -1);
        clone0.le("DATEDIFF( NOW(), last_follow_time )", 7);
        Customer customer0 = baseMapper.selectOne(clone0);

        QueryWrapper<Customer> clone = query.clone();
        clone.select("count(1) as count");
        clone.gt("DATEDIFF( NOW(), last_follow_time )", 7);
        clone.le("DATEDIFF( NOW(), last_follow_time )", 30);
        Customer customer = baseMapper.selectOne(clone);

        QueryWrapper<Customer> clone1 = query.clone();
        clone1.select("count(1) as count");
        clone1.gt("DATEDIFF( NOW(), last_follow_time )", 30);
        clone1.le("DATEDIFF( NOW(), last_follow_time )", 180);
        Customer customer1 = baseMapper.selectOne(clone1);

        QueryWrapper<Customer> clone2 = query.clone();
        clone2.select("count(1) as count");
        clone2.and(q -> q
                .gt("DATEDIFF( NOW(), last_follow_time )", 180)
                .or().isNull("last_follow_time")
        );

        Customer customer2 = baseMapper.selectOne(clone2);

        //返回最终结果
        Map<String, Object> map = new HashMap<>();
        map.put("0", customer0.getCount());
        map.put("7", customer.getCount());
        map.put("30", customer1.getCount());
        map.put("180", customer2.getCount());
        return map;
    }

    @Override
    public Map<String, Object> tagStatistics(CustomerSelectDto customerDto) {
        if (ObjectUtil.isEmpty(customerDto) && ObjectUtil.isEmpty(customerDto.getStatisticsType())) {
            throw new ServiceException("参数异常：统计类型不能为null");
        }
        QueryWrapper<Customer> query = Wrappers.query();
        if (ObjectUtil.isNotEmpty(customerDto.getType())) {
            // 私海客户查询
            if (customerDto.getType().equals("1")) {
                query.isNotNull("user_id");
                // 私海客户需要添加权限（自己查自己）
                query.eq("user_id", SecurityUtils.getUserId());
            } else if (customerDto.getType().equals("0")) {// 公海客户
                query.and(wrapper1 -> wrapper1.isNull("user_id").or().eq("user_id", ""));
            }
        }

        //将标签合在一起
        query.select("IFNULL(tag,'') as tag");
        List<Customer> customerList = this.list(query);

        Integer sumCount = 0;
        Map<String, Integer> map = new HashMap<>();
        if (ObjectUtil.isNotEmpty(customerList)) {
            for (Customer customer : customerList) {
                String tags = customer.getTag();
                List<String> tagList = Arrays.stream(tags.split(",")).distinct().collect(Collectors.toList());
                for (String tag : tagList) {
                    Integer count = map.getOrDefault(tag, 0);
                    map.put(tag, ++count);
                    sumCount++;
                }
            }
        }

        List<Customer> arr = new ArrayList<>();
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            Customer customer1 = new Customer();
            customer1.setTag(entry.getKey());
            customer1.setCount(entry.getValue());
            arr.add(customer1);
        }

        Map<String, Object> reData = new HashMap<>();
        reData.put("countAmount", sumCount);
        reData.put("customerList", arr);

        return reData;
    }

    /**
     * 客户分配
     */
    @Override
    public void customerAllocation(CustomerDto dto) {
        baseMapper.customerAllocation(dto);
    }

    @Override
    public List<Long> getAuthIdList() {
        List<Long> authUserIdList = UserUtil.getAuthUserIdList();
        return listObject(Customer::getId, q -> q.in(Customer::getUserId, authUserIdList));
    }

    @Override
    public CustomerCodeAndCountryId getCustomerCodeAndCountryId(Long customerId) {
        if (customerId == null) {
            throw new ServiceException("客户id不能为空");
        }

        Customer customer = getById(customerId);
        if (customer == null) {
            throw new ServiceException("未找到客户");
        }

        CustomerCodeAndCountryId customerCodeAndCountryId = new CustomerCodeAndCountryId();
        customerCodeAndCountryId.setCountryId(customer.getCountryId());
        customerCodeAndCountryId.setCustomerCode(customer.getCode());

        return customerCodeAndCountryId;
    }

    @Override
    public List<CustomerVo> getCustomerInfoByIds(List<Long> customerIds) {
        if (ObjectUtil.isEmpty(customerIds)) {
            return new ArrayList<>();
        }
        List<Customer> customerList = this.list(q -> q.in(Customer::getId, customerIds));
        if (ObjectUtil.isEmpty(customerList)) {
            return new ArrayList<>();
        }
        List<CustomerVo> customerVos = BeanUtil.copyToList(customerList, CustomerVo.class);
        Map<Long, List<CustomerUser>> customerUserMap = customerUserService.mapKGroup(CustomerUser::getCustomerId,
                q -> q.in(CustomerUser::getCustomerId, customerIds));
        for (CustomerVo customerVo : customerVos) {
            customerVo.setCustomerUserList(customerUserMap.get(customerVo.getId()));
        }
        //赋值国家信息
        CustomizeAreaUtil.setAreaName(customerVos);

        return customerVos;
    }
}
