package com.cpop.oam.business.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.cpop.common.utils.StringUtils;
import com.cpop.common.utils.bean.BeanUtils;
import com.cpop.core.base.entity.PageDomain;
import com.cpop.core.base.exception.ServiceException;
import com.cpop.core.service.RedisService;
import com.cpop.core.utils.SecurityUtils;
import com.cpop.core.utils.SpringUtils;
import com.cpop.core.utils.sql.SqlUtils;
import com.cpop.oam.business.bo.ClueFollowUpBo;
import com.cpop.oam.business.bo.CluePutOffBo;
import com.cpop.oam.business.bo.ClueUpdateBo;
import com.cpop.oam.business.entity.*;
import com.cpop.oam.business.service.*;
import com.cpop.oam.business.vo.*;
import com.cpop.oam.framework.constant.OamRedisConstant;
import com.cpop.system.business.entity.DictData;
import com.cpop.system.business.entity.Store;
import com.cpop.system.business.service.DictDataService;
import com.cpop.system.business.service.StoreService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryOrderBy;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.cpop.oam.business.mapper.ClueMapper;
import io.swagger.models.auth.In;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;

import static com.cpop.oam.business.entity.table.CluePutOffTableDef.CLUE_PUT_OFF;
import static com.cpop.oam.business.entity.table.ClueRecordTableDef.CLUE_RECORD;
import static com.cpop.oam.business.entity.table.ClueTableDef.CLUE;
import static com.cpop.oam.business.entity.table.ClueUpdateTableDef.CLUE_UPDATE;
import static com.cpop.oam.business.entity.table.SignAreaTableDef.SIGN_AREA;
import static com.cpop.oam.business.entity.table.SignGoalTableDef.SIGN_GOAL;
import static com.cpop.oam.business.entity.table.StaffTableDef.STAFF;
import static com.cpop.system.business.entity.table.BrandTableDef.BRAND;
import static com.cpop.system.business.entity.table.StoreSignTableDef.STORE_SIGN;
import static com.cpop.system.business.entity.table.StoreTableDef.STORE;
import static com.mybatisflex.core.query.QueryMethods.*;

/**
 * 线索表 服务层实现。
 *
 * @author DB
 * @since 2024-02-19
 */
@Service("clueService")
public class ClueServiceImpl extends ServiceImpl<ClueMapper, Clue> implements ClueService {

    /**
     * 个人线索分页
     * @author DB
     * @since 2024/2/19
     * @return R<Page<SignGoalPageVo>>
     */
    @Override
    public Page<CluePageVo> getPersonCluePage(Integer clueStatus, String city, String brandId, String storeId, String chargeOrPhone, String staffId, String signMonth,Integer followStatus) {
        PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
        QueryWrapper queryWrapper = QueryWrapper.create();
        if (clueStatus != null){
            //待签约
            if (clueStatus == 0){
                queryWrapper.and(CLUE.CLUE_STATUS.in(0, 2));
            } else {
                queryWrapper.and(CLUE.CLUE_STATUS.eq(clueStatus));
            }
        }
        if (StringUtils.isNotBlank(staffId)) {
            queryWrapper.and(CLUE.RESPONSIBLE_STAFF_ID.eq(staffId));
        } else {
            JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
            queryWrapper.and(CLUE.RESPONSIBLE_STAFF_ID.eq(loginUserInfo.getString("id")));
        }
        if (StringUtils.isNotBlank(city) && StringUtils.equals("其他", city)) {
            int year = LocalDate.now().getYear();
            List<String> cityList = SpringUtils.getBean(SignAreaService.class).queryChain()
                    .select(distinct(SIGN_AREA.CITY))
                    .leftJoin(SIGN_GOAL).on(SIGN_GOAL.ID.eq(SIGN_AREA.SIGN_GOAL_ID))
                    .and(SIGN_GOAL.YEAR.eq(year))
                    .listAs(String.class);
            if (cityList == null || cityList.isEmpty()) {
                throw new ServiceException("当前年没有设置签约指标,请先设置后再进行操作");
            }
            //地区
            queryWrapper.and(CLUE.CITY.notIn(cityList));
        } else if (StringUtils.isNotBlank(city)) {
            //地区
            queryWrapper.and(CLUE.CITY.eq(city));
        }
        return this.mapper.paginateAs(Page.of(pageDomain.getPageNum(),pageDomain.getPageSize()),
                queryWrapper
                        .select(CLUE.CITY,CLUE.ID,CLUE.CREATE_TIME,CLUE.DEV_STAFF_ID,CLUE.LAST_FOLLOW_UP_TIME,CLUE.LAST_FOLLOW_UP_CONTENT,CLUE.RECEIPT_TIME,CLUE.STORE_ID,CLUE.CLUE_STATUS,
                                CLUE.FOLLOW_STATUS)
                        .select(STORE.STORE_NAME,STORE.STORE_ADDR,STORE.PERSON_CHARGE,STORE.PHONE)
                        .select(BRAND.BRAND_NAME)
                        .select(STORE_SIGN.EXPIRE_DATE,STORE_SIGN.CREATE_TIME.as(CluePageVo::getStoreSignTime))
                        // 跟进间隔
                        .select(dateDiff(now(), CLUE.LAST_FOLLOW_UP_TIME).as(CluePageVo::getFollowUpInterval))
                        // 签约时间
                        .select(dateDiff(now(), CLUE.RECEIPT_TIME).as(CluePageVo::getSignInterval))
                        .from(CLUE)
                        .leftJoin(STORE).on(STORE.ID.eq(CLUE.STORE_ID))
                        .leftJoin(BRAND).on(BRAND.ID.eq(STORE.BRAND_ID))
                        .leftJoin(STORE_SIGN).on(STORE_SIGN.STORE_ID.eq(STORE.ID))
                        //品牌
                        .and(BRAND.ID.eq(brandId))
                        //校区
                        .and(CLUE.STORE_ID.eq(storeId))
                        .and(CLUE.FOLLOW_STATUS.eq(followStatus))
                        .and(STORE.PERSON_CHARGE.likeLeft(chargeOrPhone).or(STORE.PHONE.eq(chargeOrPhone)))
                        .and(STORE_SIGN.SIGN_MONTH.eq(signMonth))
                        .orderBy(changeOrderColumn(pageDomain)),
                CluePageVo.class,
                //开发员工
                item -> item.field(CluePageVo::getDevStaffName)
                        .queryWrapper(devStaff -> queryChain().select(STAFF.NAME.as(CluePageVo::getDevStaffName))
                                .from(STAFF)
                                .where(STAFF.ID.eq(devStaff.getDevStaffId()))));
    }

    /**
     * 排序调整
     * @author DB
     * @since 2024/2/20
     * @param pageDomain 排序请求参数
     * @return QueryOrderBy
     */
    private QueryOrderBy changeOrderColumn(PageDomain pageDomain) {
        switch (pageDomain.getOrderByColumn()) {
            case "createTime":
                if (pageDomain.getBoolAsc()) {
                    return CLUE.CREATE_TIME.asc();
                } else {
                    return CLUE.CREATE_TIME.desc();
                }
            case "receiptTime":
                if (pageDomain.getBoolAsc()) {
                    return CLUE.RECEIPT_TIME.asc();
                } else {
                    return CLUE.RECEIPT_TIME.desc();
                }
            case "followUpInterval":
                if (pageDomain.getBoolAsc()) {
                    return column("follow_up_interval").asc();
                } else {
                    return column("follow_up_interval").desc();
                }
            case "signInterval":
                if (pageDomain.getBoolAsc()) {
                    return column("sign_interval").asc();
                } else {
                    return column("sign_interval").desc();
                }
            default:
                return CLUE.CREATE_TIME.desc();
        }
    }

    /**
     * 个人签约目标
     * @author DB
     * @since 2024/2/20
     * @param signMonth 签约月份
     * @return PersonSignGoalVo
     */
    @Override
    public PersonSignGoalVo getPersonSignGoal(String signMonth,String staffId) {
        QueryWrapper queryWrapper = QueryWrapper.create();
        if (StringUtils.isNotBlank(staffId)) {
            queryWrapper.and(SIGN_GOAL.STAFF_ID.eq(staffId));
        } else {
            JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
            queryWrapper.and(SIGN_GOAL.STAFF_ID.eq(loginUserInfo.getString("id")));
            staffId = loginUserInfo.getString("id");
        }
        SignGoalService signGoalService = SpringUtils.getBean(SignGoalService.class);
        if (StringUtils.isBlank(signMonth)) {
            signMonth = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM"));
        }
        String[] split = signMonth.split("-");
        SignGoal signGoal = signGoalService.getOne(queryWrapper.where(SIGN_GOAL.YEAR.eq(Integer.parseInt(split[0]))));
        PersonSignGoalVo vo = new PersonSignGoalVo();
        Long signNum = this.count(QueryWrapper.create().where(CLUE.RESPONSIBLE_STAFF_ID.eq(staffId)).and(CLUE.CLUE_STATUS.eq(1)));
        vo.setSignNum(signNum.intValue());
        Long totalNum = this.count(QueryWrapper.create().where(CLUE.RESPONSIBLE_STAFF_ID.eq(staffId)));
        vo.setTotalNum(totalNum.intValue());
        if (signGoal == null){
            return vo;
        }
        switch (Integer.parseInt(split[1])){
            case 1:
                vo.setGoalNum(signGoal.getJanGoal());
                vo.setFinishNum(signGoal.getJanFinish());
                break;
            case 2:
                vo.setGoalNum(signGoal.getFebGoal());
                vo.setFinishNum(signGoal.getFebFinish());
                break;
            case 3:
                vo.setGoalNum(signGoal.getMarGoal());
                vo.setFinishNum(signGoal.getMarFinish());
                break;
            case 4:
                vo.setGoalNum(signGoal.getAprGoal());
                vo.setFinishNum(signGoal.getAprFinish());
                break;
            case 5:
                vo.setGoalNum(signGoal.getMayGoal());
                vo.setFinishNum(signGoal.getMayFinish());
                break;
            case 6:
                vo.setGoalNum(signGoal.getJunGoal());
                vo.setFinishNum(signGoal.getJunFinish());
                break;
            case 7:
                vo.setGoalNum(signGoal.getJulGoal());
                vo.setFinishNum(signGoal.getJulFinish());
                break;
            case 8:
                vo.setGoalNum(signGoal.getAugGoal());
                vo.setFinishNum(signGoal.getAugFinish());
                break;
            case 9:
                vo.setGoalNum(signGoal.getSepGoal());
                vo.setFinishNum(signGoal.getSepFinish());
                break;
            case 10:
                vo.setGoalNum(signGoal.getOctGoal());
                vo.setFinishNum(signGoal.getOctFinish());
                break;
            case 11:
                vo.setGoalNum(signGoal.getNovGoal());
                vo.setFinishNum(signGoal.getNovFinish());
                break;
            case 12:
                vo.setGoalNum(signGoal.getDecGoal());
                vo.setFinishNum(signGoal.getDecFinish());
                break;
        }
        return vo;
    }

    /**
     * 线索跟进
     * @author DB
     * @since 2024/2/20
     */
    @Override
    public void clueFollowUp(ClueFollowUpBo bo) {
        ClueRecord clueRecord = BeanUtils.mapToClass(bo, ClueRecord.class);
        clueRecord.setRecordType(2);
        JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
        clueRecord.setRecordStaffId(loginUserInfo.getString("id"));
        SpringUtils.getBean(ClueRecordService.class).save(clueRecord);
        SpringUtils.getBean(ClueService.class).updateChain()
                .set(CLUE.LAST_FOLLOW_UP_TIME, LocalDateTime.now())
                .set(CLUE.LAST_FOLLOW_UP_CONTENT,bo.getRecordContent())
                .where(CLUE.ID.eq(bo.getClueId()))
                .update();
        //更新跟进状态
        this.updateChain()
                .set(CLUE.FOLLOW_STATUS,bo.getFollowStatus())
                .where(CLUE.ID.eq(bo.getClueId()))
                .update();
    }

    /**
     * 线索更新
     * @author DB
     * @since 2024/2/20
     * @param bo 请求对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void clueUpdate(ClueUpdateBo bo) {
        Clue clue = this.getById(bo.getClueId());
        StoreService storeService = SpringUtils.getBean(StoreService.class);
        Store store = storeService.getById(clue.getStoreId());
        ClueUpdate clueUpdate = BeanUtils.mapToClass(bo,ClueUpdate.class);
        clueUpdate.setOldPersonCharge(store.getPersonCharge())
                .setOldPhone(store.getPhone())
                .setOldStoreAddr(store.getStoreAddr())
                .setOldStoreName(store.getStoreName());
        JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
        clueUpdate.setUpdateStaffId(loginUserInfo.getString("id"));
        //保存记录
        SpringUtils.getBean(ClueUpdateService.class).save(clueUpdate);
        ClueRecord clueRecord = new ClueRecord();
        clueRecord.setClueId(bo.getClueId())
                .setRecordStaffId(loginUserInfo.getString("id"))
                .setRecordType(6)
                .setRecordContent("校区更新");
        SpringUtils.getBean(ClueRecordService.class).save(clueRecord);
        //更新校区
        store.setStoreName(bo.getNewStoreName())
                .setPersonCharge(bo.getNewPersonCharge())
                .setPhone(bo.getNewPhone())
                .setStoreAddr(bo.getNewStoreAddr());
        storeService.updateById(store);
    }

    /**
     * 线索更新记录
     * @author DB
     * @since 2024/2/20
     * @param clueId 线索id
     * @return ClueUpdateVo
     */
    @Override
    public ClueUpdateVo getClueUpdateRecord(String clueId) {
        ClueUpdateVo clueUpdateVo = new ClueUpdateVo();
        List<ClueUpdateVo.ClueUpdateRecordVo> recordVos = SpringUtils.getBean(ClueUpdateService.class).queryChain()
                .select(CLUE_UPDATE.NEW_PERSON_CHARGE,CLUE_UPDATE.NEW_PHONE,CLUE_UPDATE.NEW_STORE_ADDR,CLUE_UPDATE.NEW_STORE_NAME,
                        CLUE_UPDATE.OLD_PERSON_CHARGE,CLUE_UPDATE.OLD_PHONE,CLUE_UPDATE.OLD_STORE_ADDR,CLUE_UPDATE.OLD_STORE_NAME,CLUE_UPDATE.CREATE_TIME)
                .select(STAFF.NAME.as(ClueUpdateVo.ClueUpdateRecordVo::getStaffName))
                .leftJoin(STAFF).on(STAFF.ID.eq(CLUE_UPDATE.UPDATE_STAFF_ID))
                .where(CLUE_UPDATE.CLUE_ID.eq(clueId))
                .orderBy(CLUE_UPDATE.CREATE_TIME.desc())
                .listAs(ClueUpdateVo.ClueUpdateRecordVo.class);
        clueUpdateVo.setRecordVos(recordVos);
        //获取现有校区数据
        Clue clue = this.getById(clueId);
        Store store = SpringUtils.getBean(StoreService.class).getById(clue.getStoreId());
        clueUpdateVo.setStoreName(store.getStoreName())
                .setPhone(store.getPhone())
                .setPersonCharge(store.getPersonCharge())
                .setStoreAddr(store.getStoreAddr());
        return clueUpdateVo;
    }

    /**
     * 线索延期
     * @author DB
     * @since 2024/2/20
     * @param bo 请求对象
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cluePutOff(CluePutOffBo bo) {
        //查询延期记录
        JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
        CluePutOffService cluePutOffService = SpringUtils.getBean(CluePutOffService.class);
        long count = cluePutOffService.count(QueryWrapper.create()
                .where(CLUE_PUT_OFF.AUDIT_STATUS.eq(0))
                .and(CLUE_PUT_OFF.CLUE_ID.eq(bo.getClueId())));
        if (count > 0) {
            throw new ServiceException("该线索在审核中，请勿重复提交");
        }
        CluePutOff cluePutOff = BeanUtils.mapToClass(bo, CluePutOff.class);
        cluePutOff.setAuditStatus(0)
                .setPutOffStaffId(loginUserInfo.getString("id"));
        cluePutOffService.save(cluePutOff);
        ClueRecord clueRecord = new ClueRecord();
        clueRecord.setClueId(bo.getClueId())
                .setRecordStaffId(loginUserInfo.getString("id"))
                .setRecordType(7)
                .setRecordContent(bo.getPutOffReason());
        SpringUtils.getBean(ClueRecordService.class).save(clueRecord);
    }

    /**
     * 线索延期记录
     * @author DB
     * @since 2024/2/20
     * @param clueId 线索id
     * @return R<List<CluePutOffVo>>
     */
    @Override
    public List<CluePutOffVo> getCluePutOffRecord(String clueId) {
        return SpringUtils.getBean(CluePutOffService.class).getMapper().selectListByQueryAs(QueryWrapper.create()
                        .select(CLUE_PUT_OFF.PUT_OFF_DATE, CLUE_PUT_OFF.PUT_OFF_REASON, CLUE_PUT_OFF.CREATE_TIME, CLUE_PUT_OFF.PUT_OFF_STAFF_ID, CLUE_PUT_OFF.AUDIT_STAFF_ID, CLUE_PUT_OFF.AUDIT_STATUS,
                                CLUE_PUT_OFF.CREATE_TIME,CLUE_PUT_OFF.PUT_OFF_FILE_URL)
                        .where(CLUE_PUT_OFF.CLUE_ID.eq(clueId))
                        .orderBy(CLUE_PUT_OFF.CREATE_TIME.desc()),
                CluePutOffVo.class,
                //延迟员工
                item -> item.field(CluePutOffVo::getPutOffStaffName)
                        .queryWrapper(putOffStaff -> {
                            if (StringUtils.isNotBlank(putOffStaff.getPutOffStaffId())) {
                                return queryChain().select(STAFF.NAME.as(CluePutOffVo::getPutOffStaffName))
                                        .from(STAFF)
                                        .where(STAFF.ID.eq(putOffStaff.getPutOffStaffId()));
                            } else {
                                return null;
                            }
                        }),
                //审核员工
                item -> item.field(CluePutOffVo::getAuditStaffName)
                        .queryWrapper(auditStaff -> {
                            if (StringUtils.isNotBlank(auditStaff.getAuditStaffId())) {
                                return queryChain().select(STAFF.NAME.as(CluePutOffVo::getAuditStaffName))
                                        .from(STAFF)
                                        .where(STAFF.ID.eq(auditStaff.getAuditStaffId()));
                            } else {
                                return null;
                            }
                        }));
    }

    /**
     * 线索脱离
     * @author DB
     * @since 2024/2/20
     * @param id 线索id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void clueDetachment(String id) {
        Clue clue = this.getById(id);
        if (clue.getClueStatus() == 1) {
            throw new ServiceException("当前线索已签约,不允许脱离");
        }
        this.updateChain().set(CLUE.CLUE_STATUS, 0)
                .set(CLUE.RESPONSIBLE_STAFF_ID, null)
                .set(CLUE.RECEIPT_TIME,null)
                .where(CLUE.ID.eq(clue.getId()))
                .update();
        JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
        ClueRecord clueRecord = new ClueRecord();
        clueRecord.setClueId(id)
                .setRecordStaffId(loginUserInfo.getString("id"))
                .setRecordType(4)
                .setRecordContent("主动脱离");
        SpringUtils.getBean(ClueRecordService.class).save(clueRecord);
    }

    /**
     * 地区线索分页
     * @author DB
     * @since 2024/2/21
     * @param city 城市
     * @param brandId 品牌id
     * @param storeId 校区id
     * @param chargeOrPhone 负责人或手机号
     * @return Page<CluePageVo>
     */
    @Override
    public Page<CluePageVo> getAreaCluePage(String city, String brandId, String storeId, String chargeOrPhone) {
        PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
        QueryWrapper queryWrapper = QueryWrapper.create();
        //获取员工区域信息
        JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
        int year = LocalDate.now().getYear();
        List<String> cityList = SpringUtils.getBean(SignAreaService.class).queryChain()
                .select(distinct(SIGN_AREA.CITY))
                .leftJoin(SIGN_GOAL).on(SIGN_GOAL.ID.eq(SIGN_AREA.SIGN_GOAL_ID))
                .where(SIGN_GOAL.STAFF_ID.eq(loginUserInfo.getString("id")))
                .and(SIGN_GOAL.YEAR.eq(year))
                .listAs(String.class);
        if (cityList == null || cityList.isEmpty()){
            throw new ServiceException("您尚未被分配区域,无法查看线索");
        }
        return this.mapper.paginateAs(Page.of(pageDomain.getPageNum(),pageDomain.getPageSize()), queryWrapper
                        .select(CLUE.CITY,CLUE.ID,CLUE.CREATE_TIME,CLUE.DEV_STAFF_ID,CLUE.LAST_FOLLOW_UP_TIME,CLUE.LAST_FOLLOW_UP_CONTENT,CLUE.RECEIPT_TIME,CLUE.STORE_ID,CLUE.LAST_RECEIPT_TIME,CLUE.LAST_RECEIPT_STAFF_ID)
                        .select(STORE.STORE_NAME,STORE.STORE_ADDR,STORE.PERSON_CHARGE,STORE.PHONE)
                        .select(BRAND.BRAND_NAME)
                        .select(STORE_SIGN.EXPIRE_DATE,STORE_SIGN.CREATE_TIME.as(CluePageVo::getStoreSignTime))
                        // 跟进间隔
                        .select(dateDiff(now(), CLUE.LAST_FOLLOW_UP_TIME).as(CluePageVo::getFollowUpInterval))
                        .from(CLUE)
                        .leftJoin(STORE).on(STORE.ID.eq(CLUE.STORE_ID))
                        .leftJoin(BRAND).on(BRAND.ID.eq(STORE.BRAND_ID))
                        .leftJoin(STORE_SIGN).on(STORE_SIGN.STORE_ID.eq(STORE.ID))
                        //地区
                        .and(CLUE.CITY.in(cityList))
                        .and(CLUE.CITY.eq(city))
                        //品牌
                        .and(BRAND.ID.eq(brandId))
                        //校区
                        .and(CLUE.STORE_ID.eq(storeId))
                        .and(STORE.PERSON_CHARGE.likeLeft(chargeOrPhone).or(STORE.PHONE.eq(chargeOrPhone)))
                        .and(CLUE.RESPONSIBLE_STAFF_ID.isNull())
                        .orderBy(CLUE.CREATE_TIME.desc()),
                CluePageVo.class,
                //开发员工
                item -> item.field(CluePageVo::getDevStaffName)
                        .queryWrapper(devStaff -> {
                            if (StringUtils.isNotBlank(devStaff.getDevStaffId())) {
                                return queryChain().select(STAFF.NAME.as(CluePageVo::getDevStaffName))
                                        .from(STAFF)
                                        .where(STAFF.ID.eq(devStaff.getDevStaffId()));
                            } else {
                                return null;
                            }
                        }),
                //最后领取员工
                item -> item.field(CluePageVo::getLastReceiptStaffName)
                        .queryWrapper(lastReceiptStaff -> {
                            if (StringUtils.isNotBlank(lastReceiptStaff.getLastReceiptStaffId())) {
                                return queryChain().select(STAFF.NAME.as(CluePageVo::getDevStaffName))
                                        .from(STAFF)
                                        .where(STAFF.ID.eq(lastReceiptStaff.getLastReceiptStaffId()));
                            } else {
                                return null;
                            }
                        }),
                //脱离间隔
                item -> item.field(CluePageVo::getPutOffInterval)
                        .queryWrapper(putOffInterval -> queryChain().select(dateDiff(now(), CLUE_RECORD.CREATE_TIME).as(CluePageVo::getPutOffInterval))
                                .from(CLUE_RECORD)
                                .where(CLUE_RECORD.RECORD_TYPE.eq(4))
                                .and(CLUE_RECORD.CLUE_ID.eq(putOffInterval.getId()))
                                .orderBy(CLUE_RECORD.CREATE_TIME.desc())
                                .limit(1)));
    }

    /**
     * 公共线索分页
     * @author DB
     * @since 2024/2/21
     * @param city 城市
     * @param brandId 品牌id
     * @param storeId 校区id
     * @param chargeOrPhone 负责人或手机号
     * @return Page<CluePageVo>
     */
    @Override
    public Page<CluePageVo> getPublicCluePage(String city, String brandId, String storeId, String chargeOrPhone) {
        PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
        QueryWrapper queryWrapper = QueryWrapper.create();
        /*int year = LocalDate.now().getYear();
        List<String> cityList = SpringUtils.getBean(SignAreaService.class).queryChain()
                .select(distinct(SIGN_AREA.CITY))
                .leftJoin(SIGN_GOAL).on(SIGN_GOAL.ID.eq(SIGN_AREA.SIGN_GOAL_ID))
                .and(SIGN_GOAL.YEAR.eq(year))
                .listAs(String.class);
        if (cityList == null || cityList.isEmpty()) {
            throw new ServiceException("当前年没有设置签约指标,请先设置后再进行操作");
        }
        if (!StringUtils.equals("其他", city)) {
            queryWrapper.and(CLUE.CITY.eq(city));
        }*/
        return this.mapper.paginateAs(Page.of(pageDomain.getPageNum(),pageDomain.getPageSize()), queryWrapper
                        .select(CLUE.CITY,CLUE.ID,CLUE.CREATE_TIME,CLUE.DEV_STAFF_ID,CLUE.LAST_FOLLOW_UP_TIME,CLUE.LAST_FOLLOW_UP_CONTENT,CLUE.RECEIPT_TIME,CLUE.STORE_ID,CLUE.LAST_RECEIPT_TIME,CLUE.LAST_RECEIPT_STAFF_ID)
                        .select(STORE.STORE_NAME,STORE.STORE_ADDR,STORE.PERSON_CHARGE,STORE.PHONE)
                        .select(BRAND.BRAND_NAME)
                        .select(STORE_SIGN.EXPIRE_DATE,STORE_SIGN.CREATE_TIME.as(CluePageVo::getStoreSignTime))
                        // 跟进间隔
                        .select(dateDiff(now(), CLUE.LAST_FOLLOW_UP_TIME).as(CluePageVo::getFollowUpInterval))
                        .from(CLUE)
                        .leftJoin(STORE).on(STORE.ID.eq(CLUE.STORE_ID))
                        .leftJoin(BRAND).on(BRAND.ID.eq(STORE.BRAND_ID))
                        .leftJoin(STORE_SIGN).on(STORE_SIGN.STORE_ID.eq(STORE.ID))
                        //地区
                        //.and(CLUE.CITY.notIn(cityList))
                        //品牌
                        .and(BRAND.ID.eq(brandId))
                        //校区
                        .and(CLUE.STORE_ID.eq(storeId))
                        .and(STORE.PERSON_CHARGE.likeLeft(chargeOrPhone).or(STORE.PHONE.eq(chargeOrPhone)))
                        .and(CLUE.RESPONSIBLE_STAFF_ID.isNull())
                        .orderBy(CLUE.CREATE_TIME.desc()),
                CluePageVo.class,
                //开发员工
                item -> item.field(CluePageVo::getDevStaffName)
                        .queryWrapper(devStaff -> {
                            if(StringUtils.isNotBlank(devStaff.getDevStaffId())){
                                return queryChain().select(STAFF.NAME.as(CluePageVo::getDevStaffName))
                                        .from(STAFF)
                                        .where(STAFF.ID.eq(devStaff.getDevStaffId()));
                            } else {
                                return null;
                            }
                        }),
                //最后领取员工
                item -> item.field(CluePageVo::getLastReceiptStaffName)
                        .queryWrapper(lastReceiptStaff -> {
                            if (StringUtils.isNotBlank(lastReceiptStaff.getLastReceiptStaffId())) {
                                return queryChain().select(STAFF.NAME.as(CluePageVo::getDevStaffName))
                                        .from(STAFF)
                                        .where(STAFF.ID.eq(lastReceiptStaff.getLastReceiptStaffId()));
                            } else {
                                return null;
                            }
                        }),
                //脱离间隔
                item -> item.field(CluePageVo::getPutOffInterval)
                        .queryWrapper(putOffInterval -> queryChain().select(dateDiff(now(), CLUE_RECORD.CREATE_TIME).as(CluePageVo::getPutOffInterval))
                                .from(CLUE_RECORD)
                                .where(CLUE_RECORD.RECORD_TYPE.eq(4))
                                .and(CLUE_RECORD.CLUE_ID.eq(putOffInterval.getId()))
                                .orderBy(CLUE_RECORD.CREATE_TIME.desc())
                                .limit(1)));
    }

    /**
     * 线索领取
     * @author DB
     * @since 2024/2/20
     * @param id 线索id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void clueCollection(String id) {
        //分布式锁进行幂等处理
        RedisService redisService = SpringUtils.getBean(RedisService.class);
        //分布式锁进行幂等处理
        Lock userIdLock = redisService.distributedLock(OamRedisConstant.CLUE_CLAIM_LOCK + id);
        if (userIdLock.tryLock()) {
            try {
                Clue clue = this.getById(id);
                if (StringUtils.isNotBlank(clue.getResponsibleStaffId())){
                    throw new ServiceException("当前线索已被领取,请刷新页面后重试");
                }
                JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
                if (StringUtils.isBlank(clue.getDevStaffId())) {
                    clue.setDevStaffId(loginUserInfo.getString("id"));
                }
                LocalDateTime now = LocalDateTime.now();
                String content = "员工" + loginUserInfo.getString("name") + "领取了该线索";
                clue.setResponsibleStaffId(loginUserInfo.getString("id"))
                        .setReceiptTime(now)
                        .setLastFollowUpTime(now)
                        .setLastFollowUpContent(content)
                        .setLastReceiptStaffId(loginUserInfo.getString("id"))
                        .setLastReceiptTime(now);
                this.updateById(clue);
                //插入记录
                ClueRecord clueRecord = new ClueRecord();
                clueRecord.setClueId(id)
                        .setRecordType(1)
                        .setRecordStaffId(loginUserInfo.getString("id"))
                        .setRecordContent(content);
                SpringUtils.getBean(ClueRecordService.class).save(clueRecord);
            }catch (Exception e) {
                throw new ServiceException(e.getMessage());
            } finally {
                //释放锁
                userIdLock.unlock();
            }
        } else {
            //获取锁失败，直接返回空
            throw new ServiceException("请勿重复领取");
        }

    }

    /**
     * 我的开发分页
     * @author DB
     * @since 2024/2/21
     * @param city 城市
     * @param brandId 品牌id
     * @param storeId 校区id
     * @param chargeOrPhone 负责人或手机号
     * @return Page<CluePageVo>
     */
    @Override
    public Page<CluePageVo> getMyDevCluePage(String city, String brandId, String storeId, String chargeOrPhone) {
        PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
        QueryWrapper queryWrapper = QueryWrapper.create();
        JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
        if (StringUtils.isNotBlank(city) && StringUtils.equals("其他", city)) {
            List<String> dictValues = SpringUtils.getBean(DictDataService.class).getDictDataByDictType("oam_clue_area")
                    .stream().map(DictData::getDictValue).collect(Collectors.toList());
            if (dictValues.isEmpty()) {
                throw new ServiceException("没有设置线索区域字典,请先设置后再进行操作");
            }
            List<String> cityList = new ArrayList<>();
            dictValues.forEach(item -> {
                cityList.addAll(Arrays.asList(item.split("/")));
            });
            queryWrapper.and(CLUE.CITY.notIn(cityList));
        } else if (StringUtils.isNotBlank(city)) {
            queryWrapper.and(CLUE.CITY.eq(city));
        }
        return this.mapper.paginateAs(Page.of(pageDomain.getPageNum(),pageDomain.getPageSize()),
                queryWrapper
                        .select(CLUE.CITY,CLUE.ID,CLUE.CREATE_TIME,CLUE.DEV_STAFF_ID,CLUE.LAST_FOLLOW_UP_TIME,CLUE.LAST_FOLLOW_UP_CONTENT,CLUE.RECEIPT_TIME,CLUE.STORE_ID,CLUE.RESPONSIBLE_STAFF_ID,
                                CLUE.CLUE_STATUS)
                        .select(STORE.STORE_NAME,STORE.STORE_ADDR,STORE.PERSON_CHARGE,STORE.PHONE)
                        .select(BRAND.BRAND_NAME)
                        .select(STORE_SIGN.CREATE_TIME.as(CluePageVo::getStoreSignTime))
                        // 跟进间隔
                        .select(dateDiff(now(), CLUE.LAST_FOLLOW_UP_TIME).as(CluePageVo::getFollowUpInterval))
                        // 签约时间
                        .select(dateDiff(now(), CLUE.RECEIPT_TIME).as(CluePageVo::getSignInterval))
                        .from(CLUE)
                        .leftJoin(STORE).on(STORE.ID.eq(CLUE.STORE_ID))
                        .leftJoin(BRAND).on(BRAND.ID.eq(STORE.BRAND_ID))
                        .leftJoin(STORE_SIGN).on(STORE_SIGN.STORE_ID.eq(STORE.ID))
                        .and(CLUE.DEV_STAFF_ID.eq(loginUserInfo.getString("id")))
                        //品牌
                        .and(BRAND.ID.eq(brandId))
                        //校区
                        .and(CLUE.STORE_ID.eq(storeId))
                        .and(STORE.PERSON_CHARGE.likeLeft(chargeOrPhone).or(STORE.PHONE.eq(chargeOrPhone)))
                        .orderBy(CLUE.CREATE_TIME.desc()),
                CluePageVo.class,
                //开发员工
                item -> item.field(CluePageVo::getDevStaffName)
                        .queryWrapper(devStaff -> queryChain().select(STAFF.NAME.as(CluePageVo::getDevStaffName))
                                .from(STAFF)
                                .where(STAFF.ID.eq(devStaff.getDevStaffId()))),
                //负责员工
                item -> item.field(CluePageVo::getResponsibleStaffName)
                        .queryWrapper(responsibleStaff -> {
                            if (StringUtils.isNotBlank(responsibleStaff.getResponsibleStaffId())){
                                return queryChain().select(STAFF.NAME.as(CluePageVo::getResponsibleStaffName))
                                        .from(STAFF)
                                        .where(STAFF.ID.eq(responsibleStaff.getResponsibleStaffId()));
                            } else {
                                return null;
                            }
                        }));
    }
}
