package org.hzhub.crm.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hzhub.common.core.constant.SystemConstants;
import org.hzhub.common.core.exception.ServiceException;
import org.hzhub.common.core.utils.MapstructUtils;
import org.hzhub.common.core.utils.StringUtils;
import org.hzhub.common.mybatis.core.page.PageQuery;
import org.hzhub.common.mybatis.core.page.TableDataInfo;
import org.hzhub.common.satoken.utils.LoginHelper;
import org.hzhub.crm.domain.CrmDealer;
import org.hzhub.crm.domain.CrmLead;
import org.hzhub.crm.domain.CrmLeadFollow;
import org.hzhub.crm.domain.bo.CrmDealerBo;
import org.hzhub.crm.domain.bo.CrmLeadBo;
import org.hzhub.crm.domain.bo.CrmLeadConvertBo;
import org.hzhub.crm.domain.bo.CrmLeadFollowBo;
import org.hzhub.crm.domain.vo.CrmDealerVo;
import org.hzhub.crm.domain.vo.CrmLeadFollowVo;
import org.hzhub.crm.domain.vo.CrmLeadStatsVo;
import org.hzhub.crm.domain.vo.CrmLeadVo;
import org.hzhub.crm.mapper.CrmDealerMapper;
import org.hzhub.crm.mapper.CrmLeadFollowMapper;
import org.hzhub.crm.mapper.CrmLeadMapper;
import org.hzhub.crm.service.ErpIntegrationService;
import org.hzhub.crm.service.ICrmLeadService;
import org.hzhub.crm.service.ICrmOpportunityService;
import org.hzhub.crm.service.CustomerSyncService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * CRM线索 Service 实现
 *
 * @author hzhub
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class CrmLeadServiceImpl implements ICrmLeadService {

    private final CrmLeadMapper leadMapper;
    private final CrmLeadFollowMapper followMapper;
    private final CrmDealerMapper dealerMapper;
    private final ErpIntegrationService erpIntegrationService;
    private final ICrmOpportunityService opportunityService;
    private final CustomerSyncService customerSyncService;

    @Override
    public TableDataInfo<CrmLeadVo> selectPageLeadList(CrmLeadBo lead, PageQuery pageQuery) {
        LambdaQueryWrapper<CrmLead> wrapper = buildQueryWrapper(lead);
        Page<CrmLeadVo> page = leadMapper.selectVoPage(pageQuery.build(), wrapper);
        return TableDataInfo.build(page);
    }

    /**
     * 构建查询条件
     */
    private LambdaQueryWrapper<CrmLead> buildQueryWrapper(CrmLeadBo lead) {
        Map<String, Object> params = lead.getParams();
        LambdaQueryWrapper<CrmLead> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CrmLead::getDelFlag, SystemConstants.NORMAL)
            .like(StringUtils.isNotBlank(lead.getCompanyName()), CrmLead::getCompanyName, lead.getCompanyName())
            .eq(StringUtils.isNotBlank(lead.getMobile()), CrmLead::getMobile, lead.getMobile())
            .eq(StringUtils.isNotBlank(lead.getIntentLevel()), CrmLead::getIntentLevel, lead.getIntentLevel())
            .eq(StringUtils.isNotBlank(lead.getRiskLevel()), CrmLead::getRiskLevel, lead.getRiskLevel())
            .eq(ObjectUtil.isNotNull(lead.getOwnerUserId()), CrmLead::getOwnerUserId, lead.getOwnerUserId())
            .eq(StringUtils.isNotBlank(lead.getLeadStatus()), CrmLead::getLeadStatus, lead.getLeadStatus())
            .eq(StringUtils.isNotBlank(lead.getSourceType()), CrmLead::getSourceType, lead.getSourceType())
            .eq(StringUtils.isNotBlank(lead.getCustomerCode()), CrmLead::getCustomerCode, lead.getCustomerCode())
            .between(params.get("beginTime") != null && params.get("endTime") != null,
                CrmLead::getCreateTime, params.get("beginTime"), params.get("endTime"))
            .orderByDesc(CrmLead::getCreateTime);
        return wrapper;
    }

    @Override
    public CrmLeadVo selectLeadById(Long leadId) {
        CrmLeadVo lead = leadMapper.selectVoById(leadId);
        if (ObjectUtil.isNull(lead)) {
            return lead;
        }
        return lead;
    }

    @Override
    public CrmLeadStatsVo getLeadStats() {
        String tenantId = LoginHelper.getTenantId();

        CrmLeadStatsVo stats = new CrmLeadStatsVo();

        // 总数统计
        Long totalCount = leadMapper.countTotal(tenantId);
        stats.setTotalCount(totalCount);

        // 高意向线索数量
        Long highIntentCount = leadMapper.countHighIntent(tenantId);
        stats.setHighIntentCount(highIntentCount);

        // 本月/上月时间计算
        LocalDate now = LocalDate.now();
        int currentYear = now.getYear();
        int currentMonth = now.getMonthValue();
        int lastMonth = currentMonth == 1 ? 12 : currentMonth - 1;
        int lastMonthYear = currentMonth == 1 ? currentYear - 1 : currentYear;

        // 本月新增
        Long monthlyNewCount = leadMapper.countMonthlyNew(tenantId, currentYear, currentMonth);
        stats.setMonthlyNewCount(monthlyNewCount);

        // 上月新增
        Long lastMonthNewCount = leadMapper.countMonthlyNew(tenantId, lastMonthYear, lastMonth);
        stats.setLastMonthNewCount(lastMonthNewCount);

        // 已转化数量
        Long convertedCount = leadMapper.countConverted(tenantId);
        stats.setConvertedCount(convertedCount);

        // 转化率
        if (totalCount > 0) {
            BigDecimal rate = BigDecimal.valueOf(convertedCount * 100)
                .divide(BigDecimal.valueOf(totalCount), 2, RoundingMode.HALF_UP);
            stats.setConversionRate(rate);
        } else {
            stats.setConversionRate(BigDecimal.ZERO);
        }

        // 本月转化
        Long monthlyConvertedCount = leadMapper.countMonthlyConverted(tenantId, currentYear, currentMonth);
        stats.setMonthlyConvertedCount(monthlyConvertedCount);

        // 上月转化
        Long lastMonthConvertedCount = leadMapper.countMonthlyConverted(tenantId, lastMonthYear, lastMonth);
        stats.setLastMonthConvertedCount(lastMonthConvertedCount);

        // 本月高意向
        Long monthlyHighIntentCount = leadMapper.countMonthlyHighIntent(tenantId, currentYear, currentMonth);
        stats.setMonthlyHighIntentCount(monthlyHighIntentCount);

        // 上月高意向
        Long lastMonthHighIntentCount = leadMapper.countMonthlyHighIntent(tenantId, lastMonthYear, lastMonth);
        stats.setLastMonthHighIntentCount(lastMonthHighIntentCount);

        return stats;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertLead(CrmLeadBo lead) {
        // 如果提供了customerCode，从ERP拉取客户信息
        if (StringUtils.isNotBlank(lead.getCustomerCode())) {
            enrichLeadFromErp(lead);
        }

        // 校验手机号唯一性
        if (!checkMobileUnique(lead)) {
            throw new ServiceException("手机号已存在");
        }

        // 设置默认状态
        if (StringUtils.isBlank(lead.getLeadStatus())) {
            lead.setLeadStatus("new");
        }

        // 设置创建人为当前用户
        if (ObjectUtil.isNull(lead.getCreateBy())) {
            lead.setCreateBy(LoginHelper.getUserId());
        }

        CrmLead crmLead = MapstructUtils.convert(lead, CrmLead.class);
        return leadMapper.insert(crmLead);
    }

    /**
     * 从ERP拉取客户信息并填充线索
     */
    private void enrichLeadFromErp(CrmLeadBo lead) {
        try {
            Map<String, Object> customerDetail = erpIntegrationService.getCustomerDetail(lead.getCustomerCode());
            if (customerDetail != null) {
                // 从ERP客户信息填充线索基础信息（如果未提供）
                if (StringUtils.isBlank(lead.getCompanyName())) {
                    lead.setCompanyName((String) customerDetail.get("customerName"));
                }
                if (StringUtils.isBlank(lead.getContactName())) {
                    lead.setContactName((String) customerDetail.get("contactName"));
                }
                if (StringUtils.isBlank(lead.getMobile())) {
                    lead.setMobile((String) customerDetail.get("phone"));
                }
                if (StringUtils.isBlank(lead.getProvince())) {
                    lead.setProvince((String) customerDetail.get("province"));
                }
                if (StringUtils.isBlank(lead.getCity())) {
                    lead.setCity((String) customerDetail.get("city"));
                }

                log.info("成功从ERP拉取客户信息: customerCode={}", lead.getCustomerCode());
            } else {
                log.warn("ERP客户信息获取失败: customerCode={}", lead.getCustomerCode());
            }
        } catch (Exception e) {
            log.error("从ERP拉取客户信息异常: customerCode={}", lead.getCustomerCode(), e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int updateLead(CrmLeadBo lead) {
        // 校验线索是否存在
        CrmLead existingLead = leadMapper.selectById(lead.getLeadId());
        if (ObjectUtil.isNull(existingLead)) {
            throw new ServiceException("线索不存在");
        }

        // 校验手机号唯一性
        if (!checkMobileUnique(lead)) {
            throw new ServiceException("手机号已存在");
        }

        CrmLead crmLead = MapstructUtils.convert(lead, CrmLead.class);
        return leadMapper.updateById(crmLead);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteLeadByIds(Long[] leadIds) {
        List<Long> ids = List.of(leadIds);
        return leadMapper.deleteByIds(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int assignLead(Long leadId, Long ownerUserId) {
        // 校验线索是否存在
        CrmLead existingLead = leadMapper.selectById(leadId);
        if (ObjectUtil.isNull(existingLead)) {
            throw new ServiceException("线索不存在");
        }

        // 更新负责人和状态
        return leadMapper.update(null,
            new LambdaUpdateWrapper<CrmLead>()
                .set(CrmLead::getOwnerUserId, ownerUserId)
                .set(CrmLead::getLeadStatus, "following")
                .set(CrmLead::getUpdateTime, new Date())
                .set(CrmLead::getUpdateBy, LoginHelper.getUserId())
                .eq(CrmLead::getLeadId, leadId));
    }

    @Override
    public List<CrmLeadFollowVo> selectFollowRecordsByLeadId(Long leadId) {
        LambdaQueryWrapper<CrmLeadFollow> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(CrmLeadFollow::getLeadId, leadId)
            .eq(CrmLeadFollow::getDelFlag, SystemConstants.NORMAL)
            .orderByDesc(CrmLeadFollow::getCreateTime);
        return followMapper.selectVoList(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertFollowRecord(CrmLeadFollowBo follow) {
        // 设置跟进人为当前用户
        if (ObjectUtil.isNull(follow.getFollowUserId())) {
            follow.setFollowUserId(LoginHelper.getUserId());
        }

        CrmLeadFollow crmFollow = MapstructUtils.convert(follow, CrmLeadFollow.class);
        int result = followMapper.insert(crmFollow);

        // 如果提供了下次跟进时间，更新线索的nextFollowTime
        if (ObjectUtil.isNotNull(follow.getNextFollowTime()) && result > 0) {
            leadMapper.update(null,
                new LambdaUpdateWrapper<CrmLead>()
                    .set(CrmLead::getNextFollowTime, crmFollow.getNextFollowTime())
                    .set(CrmLead::getUpdateTime, new Date())
                    .set(CrmLead::getUpdateBy, LoginHelper.getUserId())
                    .eq(CrmLead::getLeadId, follow.getLeadId()));
        }

        return result;
    }

    @Override
    public boolean checkMobileUnique(CrmLeadBo lead) {
        boolean exist = leadMapper.exists(new LambdaQueryWrapper<CrmLead>()
            .eq(CrmLead::getMobile, lead.getMobile())
            .ne(ObjectUtil.isNotNull(lead.getLeadId()), CrmLead::getLeadId, lead.getLeadId()));
        return !exist;
    }

    /**
     * 线索转经销商
     *
     * @param convert 转化参数
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int convertToDealer(CrmLeadConvertBo convert) {
        // 1. 查询线索
        CrmLead lead = leadMapper.selectById(convert.getLeadId());
        if (lead == null) {
            throw new ServiceException("线索不存在");
        }
        if ("converted".equals(lead.getLeadStatus())) {
            throw new ServiceException("线索已转化，不能重复转化");
        }

        // 2. 校验经销商编码唯一性
        boolean dealerCodeExists = dealerMapper.exists(new LambdaQueryWrapper<CrmDealer>()
            .eq(CrmDealer::getDealerCode, convert.getDealerCode()));
        if (dealerCodeExists) {
            throw new ServiceException("经销商编码已存在");
        }

        // 3. 【新增】校验ERP客户编码必须存在且属于当前租户
        if (StringUtils.isBlank(convert.getCustomerCode())) {
            throw new ServiceException("经销商必须绑定ERP客户编码，请选择ERP客户");
        }

        if (!customerSyncService.validateCustomerCode(convert.getCustomerCode())) {
            throw new ServiceException("ERP客户不存在或不属于当前租户: " + convert.getCustomerCode());
        }

        // 4. 创建经销商
        CrmDealer dealer = new CrmDealer();
        dealer.setCustomerCode(convert.getCustomerCode());  // 必填

        // 【新增】从ERP拉取客户信息覆盖名称和区域
        Map<String, Object> erpCustomer = erpIntegrationService.getCustomerDetail(convert.getCustomerCode());
        if (erpCustomer != null) {
            // 名称使用ERP值
            String erpName = (String) erpCustomer.get("customerName");
            dealer.setDealerName(StringUtils.isNotBlank(erpName) ? erpName : convert.getDealerName());

            // 区域使用ERP值
            dealer.setProvince((String) erpCustomer.get("province"));
            dealer.setCity((String) erpCustomer.get("city"));

            // 状态映射
            Integer erpIsStop = (Integer) erpCustomer.get("isStop");
            dealer.setLifecycle((erpIsStop != null && erpIsStop == 1) ? "churn" : "active");
        } else {
            dealer.setDealerName(convert.getDealerName());
            dealer.setLifecycle("active");
        }

        dealer.setDealerCode(convert.getDealerCode());
        dealer.setContactName(lead.getContactName());
        dealer.setMobile(lead.getMobile());
        dealer.setLevel(convert.getLevel() != null ? convert.getLevel() : "C");

        // 处理签约时间
        if (convert.getSignedAt() != null) {
            dealer.setSignedAt(cn.hutool.core.date.DateUtil.parse(convert.getSignedAt()));
        } else {
            dealer.setSignedAt(new Date());
        }

        dealer.setStoreCount(lead.getStoreCount() != null ? lead.getStoreCount() : 0);
        dealer.setTeamSize(0);
        dealer.setOwnerUserId(lead.getOwnerUserId());
        dealer.setSourceLeadId(lead.getLeadId());

        int dealerResult = dealerMapper.insert(dealer);
        if (dealerResult <= 0) {
            throw new ServiceException("创建经销商失败");
        }

        // 5. 更新线索状态
        lead.setLeadStatus("converted");
        lead.setConvertedDealerId(dealer.getDealerId());
        int leadResult = leadMapper.updateById(lead);

        log.info("线索转化成功: leadId={}, dealerId={}, dealerCode={}, customerCode={}",
            lead.getLeadId(), dealer.getDealerId(), dealer.getDealerCode(), dealer.getCustomerCode());

        return leadResult;
    }

    /**
     * 作废线索
     *
     * @param leadId 线索ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int invalidateLead(Long leadId) {
        // 查询线索
        CrmLead lead = leadMapper.selectById(leadId);
        if (lead == null) {
            throw new ServiceException("线索不存在");
        }
        if ("converted".equals(lead.getLeadStatus())) {
            throw new ServiceException("线索已转化，不能作废");
        }
        if ("invalid".equals(lead.getLeadStatus())) {
            throw new ServiceException("线索已作废");
        }

        // 更新状态为作废
        return leadMapper.update(null,
            new LambdaUpdateWrapper<CrmLead>()
                .set(CrmLead::getLeadStatus, "invalid")
                .set(CrmLead::getUpdateTime, new Date())
                .set(CrmLead::getUpdateBy, LoginHelper.getUserId())
                .eq(CrmLead::getLeadId, leadId));
    }

    /**
     * 恢复线索
     *
     * @param leadId 线索ID
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int restoreLead(Long leadId) {
        // 查询线索
        CrmLead lead = leadMapper.selectById(leadId);
        if (lead == null) {
            throw new ServiceException("线索不存在");
        }
        if (!"invalid".equals(lead.getLeadStatus())) {
            throw new ServiceException("只有已作废的线索才能恢复");
        }

        // 恢复状态为新线索或跟进中（根据是否有负责人）
        String newStatus = lead.getOwnerUserId() != null ? "following" : "new";
        return leadMapper.update(null,
            new LambdaUpdateWrapper<CrmLead>()
                .set(CrmLead::getLeadStatus, newStatus)
                .set(CrmLead::getUpdateTime, new Date())
                .set(CrmLead::getUpdateBy, LoginHelper.getUserId())
                .eq(CrmLead::getLeadId, leadId));
    }
}