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

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.cpop.common.utils.DateUtils;
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.utils.SecurityUtils;
import com.cpop.core.utils.SpringUtils;
import com.cpop.core.utils.sql.SqlUtils;
import com.cpop.oam.business.bo.BusinessDisposeBo;
import com.cpop.oam.business.bo.BusinessDistributeBo;
import com.cpop.oam.business.bo.BusinessInfoPageBo;
import com.cpop.oam.business.bo.BusinessRemoveBo;
import com.cpop.oam.business.dto.BusinessDistributeDto;
import com.cpop.oam.business.entity.*;
import com.cpop.oam.business.mapper.BusinessMapper;
import com.cpop.oam.business.service.*;
import com.cpop.oam.business.vo.BusinessInfoPageVo;
import com.cpop.oam.business.vo.BusinessPageVo;
import com.cpop.oam.business.vo.BusinessUnSignPageVo;
import com.cpop.oam.business.vo.PersonBusinessInfoVo;
import com.cpop.system.business.bo.StoreRenewBo;
import com.cpop.system.business.entity.Store;
import com.cpop.system.business.entity.StoreSign;
import com.cpop.system.business.service.StoreRenewService;
import com.cpop.system.business.service.StoreService;
import com.cpop.system.business.service.StoreSignService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.net.ssl.HttpsURLConnection;
import java.io.*;
import java.net.URL;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static com.cpop.jambox.business.entity.table.BrandExtendTableDef.BRAND_EXTEND;
import static com.cpop.jambox.business.entity.table.StoreExtendTableDef.STORE_EXTEND;
import static com.cpop.oam.business.entity.table.BusinessDetailTableDef.BUSINESS_DETAIL;
import static com.cpop.oam.business.entity.table.BusinessStaffTableDef.BUSINESS_STAFF;
import static com.cpop.oam.business.entity.table.BusinessTableDef.BUSINESS;
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.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.StoreLicenseTableDef.STORE_LICENSE;
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.distinct;
import static com.mybatisflex.core.query.QueryMethods.select;

/**
 * Oam-事务表 服务层实现。
 *
 * @author DB
 * @since 2023-12-12
 */
@Service("businessService")
public class BusinessServiceImpl extends ServiceImpl<BusinessMapper, Business> implements BusinessService {

    /**
     * 获取事务分页列表
     * @author DB
     * @since 2023/12/13
     * @param status 状态（0:进行中;1:已完成）
     * @return Page<BusinessPageVo>
     */
    @Override
    public Page<BusinessPageVo> getBusinessPage(Integer status) {
        PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
        //查询员工
        JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
        QueryWrapper queryWrapper = QueryWrapper.create();
        //运营人员
        if (loginUserInfo.getInteger("staffType") == 1) {
            queryWrapper
                    .leftJoin(BUSINESS_STAFF).on(BUSINESS_STAFF.BUSINESS_ID.eq(BUSINESS.ID))
                    .and(BUSINESS_STAFF.STAFF_ID.eq(loginUserInfo.getString("id")));
        }
        return this.mapper.paginateAs(Page.of(pageDomain.getPageNum(), pageDomain.getPageSize()),
                queryWrapper.select(BUSINESS.ID, BUSINESS.BUSINESS_LEVEL, BUSINESS.BUSINESS_TYPE, BUSINESS.DESC, BUSINESS.START_DATE, BUSINESS.END_DATE, BUSINESS.ALL_SURPLUS_QUANTITY, BUSINESS.REMARK, BUSINESS.STATUS)
                        //员工表
                        .select(STAFF.NAME.as(BusinessPageVo::getInitiatorName))
                        .leftJoin(STAFF).on(STAFF.ID.eq(BUSINESS.INITIATOR_ID))
                        .where(BUSINESS.STATUS.eq(status)),
                BusinessPageVo.class);
    }

    /**
     * 事务分发
     * @author DB
     * @since 2023/12/13
     * @param bo 请求数据
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void businessDistribute(BusinessDistributeBo bo) {
        Business business = BeanUtils.mapToClass(bo, Business.class);
        JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
        business.setInitiatorId(loginUserInfo.getString("id"))
                .setStartDate(bo.getStartAndEnd().get(0))
                .setEndDate(bo.getStartAndEnd().get(1));
        this.save(business);
        Integer allSurplusQuantity = createButtJoint(bo, business.getId());
        business.setAllSurplusQuantity(allSurplusQuantity);
        this.updateById(business);
        //TODO:定时检查事务过期？
    }

    /**
     * 事务对接
     * @author DB
     * @param bo 请求
     * @param businessId 事务id
     * @since 2023/12/13
     * @return 返回事务详情总数
     */
    private Integer createButtJoint(BusinessDistributeBo bo,String businessId) {
        //事务详情数量标记
        AtomicReference<Integer> flag = new AtomicReference<>(0);
        //读取模板
        if (bo.getButtJoint().isEmpty()){
            throw new ServiceException("对接人不能为空");
        }
        //员工相关数据
        BusinessStaffService businessStaffService = SpringUtils.getBean(BusinessStaffService.class);
        bo.getButtJoint().forEach(item -> {
            //导入数据
            List<BusinessDistributeDto> businessDistributeDataList = new ArrayList<>();
            //对接文件
            JSONObject jsonObject = JSONArray.parseArray(item.getBusinessDocUrl()).getJSONObject(0);
            String url = jsonObject.getString("url");
            InputStream fileInputStream;
            try {
                HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
                fileInputStream = connection.getInputStream();
                EasyExcel.read(fileInputStream, BusinessDistributeDto.class, new ReadListener<BusinessDistributeDto>() {

                    @Override
                    public void invoke(BusinessDistributeDto data, AnalysisContext context) {
                        businessDistributeDataList.add(data);
                    }

                    @Override
                    public void doAfterAllAnalysed(AnalysisContext context) {

                    }
                }).sheet().doRead();
                fileInputStream.close();
            } catch (IOException e) {
                throw new ServiceException("读取文件失败!");
            }
            if (businessDistributeDataList.isEmpty()) {
                throw new ServiceException("导入的excel存在空文件,请检查后重新操作");
            }
            //负责员工
            BusinessStaff businessStaff = BeanUtils.mapToClass(item, BusinessStaff.class);
            businessStaff.setBusinessId(businessId).setSurplusQuantity(businessDistributeDataList.size()).setStaffId(item.getStaffId());
            businessStaffService.save(businessStaff);
            List<BusinessDetail> businessDetails = SpringUtils.getBean(StoreService.class).queryChain()
                    .select(STORE.BRAND_ID, STORE.ID.as(BusinessDetail::getStoreId))
                    .where(STORE.ID.in(businessDistributeDataList.stream().map(BusinessDistributeDto::getStoreId).collect(Collectors.toSet())))
                    .listAs(BusinessDetail.class);
            if (businessDetails.size() != businessDistributeDataList.size()) {
                throw new ServiceException("校区查询匹配失败,请核实数据后重新提交");
            }
            businessDetails.forEach(inner -> {
                inner.setBusinessId(businessId);
                inner.setBusinessStaffId(businessStaff.getId());
            });
            //保存详情
            SpringUtils.getBean(BusinessDetailService.class).saveBatch(businessDetails);
            //批量录入
            flag.updateAndGet(v -> v + businessDetails.size());
        });
        return flag.get();
    }

    /**
     * 获取个人事务分页列表/管理人员事务详情列表
     * @author DB
     * @since 2023/12/13
     * @param bo 请求参数
     * @return Page<BusinessInfoPageVo>
     */
    @Override
    public Page<BusinessInfoPageVo> getBusinessInfoPage(BusinessInfoPageBo bo) {
        return getButtJoint(bo);
    }

    /**
     * 获取对接数据
     * @author DB
     * @since 2023/12/13
     * @param bo 请求
     * @return Page<BusinessInfoPageVo>
     */
    private Page<BusinessInfoPageVo> getButtJoint(BusinessInfoPageBo bo) {
        //获取当前员工信息
        JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
        QueryWrapper queryWrapper = QueryWrapper.create();
        //运营人员
        if (loginUserInfo.getInteger("staffType") == 1) {
            queryWrapper.and(BUSINESS_STAFF.STAFF_ID.eq(loginUserInfo.getString("id")));
        }
        PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
        return SpringUtils.getBean(BusinessDetailService.class).getMapper().paginateAs(Page.of(pageDomain.getPageNum(),pageDomain.getPageSize()),
                queryWrapper
                        //事务详情
                        .select(BUSINESS_DETAIL.ID, BUSINESS_DETAIL.DETAIL_STATUS, BUSINESS_DETAIL.DETAIL_DESC, BUSINESS_DETAIL.DETAIL_RECORD_TIME)
                        //员工
                        .select(STAFF.NAME.as(BusinessInfoPageVo::getStaffName))
                        //品牌
                        .select(BRAND.BRAND_NAME)
                        //校区
                        .select(STORE.STORE_NAME, STORE.PERSON_CHARGE, STORE.PHONE, STORE.ID.as(BusinessInfoPageVo::getStoreId))
                        //营业执照
                        .select(STORE_LICENSE.LICENSE_NAME, STORE_LICENSE.LICENSE_USER_NAME, STORE_LICENSE.LICENSE_ADDR)
                        .leftJoin(BUSINESS_STAFF).on(BUSINESS_STAFF.ID.eq(BUSINESS_DETAIL.BUSINESS_STAFF_ID))
                        .leftJoin(STAFF).on(STAFF.ID.eq(BUSINESS_STAFF.STAFF_ID))
                        .leftJoin(BRAND).on(BRAND.ID.eq(BUSINESS_DETAIL.BRAND_ID))
                        .leftJoin(STORE).on(STORE.ID.eq(BUSINESS_DETAIL.STORE_ID))
                        .leftJoin(STORE_LICENSE).on(STORE_LICENSE.STORE_ID.eq(STORE.ID))
                        .where(BUSINESS_DETAIL.BUSINESS_ID.eq(bo.getId()))
                        //品牌或校区名模糊查询
                        .and(BRAND.BRAND_NAME.like(bo.getBrandOrStore()).or(STORE.STORE_NAME.like(bo.getBrandOrStore())))
                        //校区地址或校区名模糊查询
                        .and(STORE_LICENSE.LICENSE_NAME.like(bo.getAddrOrName()).or(STORE_LICENSE.LICENSE_ADDR.like(bo.getAddrOrName())))
                        .and(BUSINESS_DETAIL.DETAIL_STATUS.eq(bo.getDetailStatus()))
                        .and(BUSINESS_STAFF.STAFF_ID.in(bo.getStaffIds())),
                BusinessInfoPageVo.class);
    }

    /**
     * 员工事务处理
     * @author DB
     * @since 2023/12/13
     * @param bo 请求
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void businessDispose(BusinessDisposeBo bo) {
        BusinessDetailService businessDetailService = SpringUtils.getBean(BusinessDetailService.class);
        BusinessDetail businessDetail;
        //查询当前事务
        if (StringUtils.isNotBlank(bo.getId())){
            businessDetail = businessDetailService.queryChain().where(BUSINESS_DETAIL.ID.eq(bo.getId())).one();
            businessDetail.setDetailStatus(bo.getDetailStatus()).setDetailDesc(bo.getDetailDesc()).setDetailRecordTime(LocalDateTime.now());
            //新增或修改
            businessDetailService.updateById(businessDetail);
        } else {
            businessDetail = new BusinessDetail();
            //获取校区数据
            Store store = SpringUtils.getBean(StoreService.class).getById(bo.getStoreId());
            JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
            //获取事务员工
            BusinessStaff businessStaff = SpringUtils.getBean(BusinessStaffService.class).getOne(QueryWrapper.create()
                    .where(BUSINESS_STAFF.BUSINESS_ID.eq(bo.getBusinessId()))
                    .and(BUSINESS_STAFF.STAFF_ID.eq(loginUserInfo.getString("id"))));
            businessDetail.setBrandId(store.getBrandId()).setStoreId(store.getId()).setBusinessId(bo.getBusinessId());
            businessDetail.setDetailStatus(bo.getDetailStatus()).setDetailDesc(bo.getDetailDesc()).setDetailRecordTime(LocalDateTime.now())
                    .setBusinessStaffId(businessStaff.getId());
            //新增或修改
            businessDetailService.save(businessDetail);
        }
        //完成的时候数量减少
        if (bo.getDetailStatus() == 1) {
            Business business = this.getById(bo.getBusinessId());
            //所有任务都完成
            if (business.getAllSurplusQuantity() == 0) {
                throw new ServiceException("当前事务已完成,请选择其他事务");
            } else if (business.getAllSurplusQuantity() - 1 == 0) {
                business.setStatus(1);
            }
            business.setAllSurplusQuantity(business.getAllSurplusQuantity() - 1);
            this.updateById(business);
            JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
            SpringUtils.getBean(BusinessStaffService.class).updateChain()
                    .setRaw(BUSINESS_STAFF.SURPLUS_QUANTITY, "surplus_quantity - 1")
                    .where(BUSINESS_STAFF.BUSINESS_ID.eq(businessDetail.getBusinessId()))
                    .and(BUSINESS_STAFF.STAFF_ID.eq(loginUserInfo.getString("id")))
                    .update();

        }
    }

    /**
     * 事务详情删除
     * @author DB
     * @since 2023/12/14
     * @param bo 删除参数
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void businessRemove(BusinessRemoveBo bo) {
        Business business = this.getById(bo.getBusinessId());
        if (bo.getId() == null) {
            //将校区改为测试校区
            SpringUtils.getBean(StoreService.class).updateChain()
                    .set(STORE.IS_TEST, true)
                    .where(STORE.ID.eq(bo.getStoreId()))
                    .update();
        } else {
            BusinessDetailService businessDetailService = SpringUtils.getBean(BusinessDetailService.class);
            BusinessDetail businessDetail = businessDetailService.getById(bo.getId());
            //机构签约
            if (business.getBusinessType() == 1) {
                //将校区改为测试校区
                SpringUtils.getBean(StoreService.class).updateChain()
                        .set(STORE.IS_TEST, true)
                        .where(STORE.ID.eq(businessDetail.getStoreId()))
                        .update();
            }
            businessDetailService.removeById(bo.getId());
        }
        //所有任务都完成
        if (business.getAllSurplusQuantity() - 1 == 0) {
            business.setStatus(1);
        }
        business.setAllSurplusQuantity(business.getAllSurplusQuantity() - 1);
        this.updateById(business);
    }

    /**
     * 获取个人当前事务详情
     * @author DB
     * @since 2023/12/29
     * @param id 事务详情id
     * @return PersonBusinessInfoVo
     */
    @Override
    public PersonBusinessInfoVo getPersonBusinessInfoById(String id) {
        JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
        return this.getOneAs(QueryWrapper.create()
                        .select(BUSINESS.BUSINESS_LEVEL,BUSINESS.BUSINESS_TYPE,BUSINESS.DESC,BUSINESS.START_DATE,BUSINESS.END_DATE,BUSINESS.REMARK)
                        .select(STAFF.NAME.as(PersonBusinessInfoVo::getInitiatorName))
                        .select(BUSINESS_STAFF.SURPLUS_QUANTITY.as(PersonBusinessInfoVo::getSurplusQuantity))
                        .leftJoin(STAFF).on(STAFF.ID.eq(BUSINESS.INITIATOR_ID))
                        .leftJoin(BUSINESS_STAFF).on(BUSINESS_STAFF.BUSINESS_ID.eq(BUSINESS.ID))
                        .where(BUSINESS.ID.eq(id))
                        .and(BUSINESS_STAFF.STAFF_ID.eq(loginUserInfo.getString("id"))),
                PersonBusinessInfoVo.class);
    }

    /**
     * 查询未签约校区分页列表
     * @author DB
     * @since 2024/1/22
     * @param params 请求参数
     * @return Page<BusinessUnSignPageVo>
     */
    @Override
    public Page<BusinessUnSignPageVo> getUnSignStorePage(String params) {
        PageDomain pageDomain = SqlUtils.getInstance().getPageDomain();
        return this.pageAs(Page.of(pageDomain.getPageNum(), pageDomain.getPageSize()),
                QueryWrapper.create()
                        .select(STORE.ID, STORE.STORE_NAME, STORE.PERSON_CHARGE, STORE.PHONE, STORE.BRAND_ID)
                        .select(BRAND.BRAND_NAME)
                        .select(STORE_LICENSE.LICENSE_PIC_URL)
                        .from(STORE)
                        .leftJoin(BRAND).on(BRAND.ID.eq(STORE.BRAND_ID))
                        .leftJoin(STORE_LICENSE).on(STORE_LICENSE.STORE_ID.eq(STORE.ID))
                        .leftJoin(STORE_SIGN).on(STORE_SIGN.ID.eq(STORE.SIGN_ID))
                        .where(STORE.SIGN_ID.isNull())
                        .and(STORE.IS_TEST.eq(false))
                        .and(STORE.STORE_NAME.like(params)
                                .or(STORE.PERSON_CHARGE.like(params)
                                        .or(STORE.PHONE.eq(params))))
                        .and(STORE.CREATE_TIME.ge(LocalDate.parse("2023-12-01", DateTimeFormatter.ofPattern("yyyy-MM-dd"))))
                        .orderBy(STORE.CREATE_TIME.desc()),
                BusinessUnSignPageVo.class);
    }

    /**
     * 校区签约
     * @author DB
     * @since 2024/1/22
     * @param id 主键
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void storeSign(String id) {
        JSONObject loginUserInfo = SecurityUtils.getInstance().getLoginUserInfo();
        StoreSign storeSign = new StoreSign();
        storeSign.setStoreId(id);
        storeSign.setSignStaffId(loginUserInfo.getString("id"));
        storeSign.setSignMonth(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM")));
        StoreSignService storeSignService = SpringUtils.getBean(StoreSignService.class);
        storeSignService.save(storeSign);
        SpringUtils.getBean(StoreService.class).updateChain()
                .set(STORE.SIGN_ID,storeSign.getId())
                .set(STORE.HAVE_COUNSELOR,true)
                .where(STORE.ID.eq(id))
                .update();
        //线索归档
        ClueService clueService = SpringUtils.getBean(ClueService.class);
        Clue clue = clueService.queryChain().where(CLUE.STORE_ID.eq(id)).one();
        clue.setClueStatus(1).setFollowStatus(6);
        clueService.updateById(clue);
        //线索记录
        ClueRecord clueRecord = new ClueRecord();
        clueRecord.setRecordType(5)
                .setClueId(clue.getId())
                .setRecordContent("机构签约")
                .setRecordStaffId(loginUserInfo.getString("id"));
        SpringUtils.getBean(ClueRecordServiceImpl.class).save(clueRecord);
        //签约目标更新
        LocalDate now = LocalDate.now();
        Month month = now.getMonth();
        int year = now.getYear();
        SignGoalService signGoalService = SpringUtils.getBean(SignGoalService.class);
        SignGoal signGoal = signGoalService.getOne(QueryWrapper.create()
                .where(SIGN_GOAL.STAFF_ID.eq(loginUserInfo.getString("id")))
                .and(SIGN_GOAL.YEAR.eq(year)));
        changeMonthGoal(signGoal,month);
        signGoalService.updateById(signGoal);
    }

    /**
     * 添加完成目标
     * @author DB
     * @since 2024/2/21
     * @param signGoal 签约目标
     * @param month 月份
     */
    private void changeMonthGoal(SignGoal signGoal, Month month) {
        switch (month) {
            case JANUARY:
                signGoal.setJanFinish(signGoal.getJanFinish() + 1);
                break;
            case FEBRUARY:
                signGoal.setFebFinish(signGoal.getFebFinish() + 1);
                break;
            case MARCH:
                signGoal.setMarFinish(signGoal.getMarFinish() + 1);
                break;
            case APRIL:
                signGoal.setAprFinish(signGoal.getAprFinish() + 1);
                break;
            case MAY:
                signGoal.setMayFinish(signGoal.getMayFinish() + 1);
                break;
            case JUNE:
                signGoal.setJunFinish(signGoal.getJunFinish() + 1);
                break;
            case JULY:
                signGoal.setJulFinish(signGoal.getJulFinish() + 1);
                break;
            case AUGUST:
                signGoal.setAugFinish(signGoal.getAugFinish() + 1);
                break;
            case SEPTEMBER:
                signGoal.setSepFinish(signGoal.getSepFinish() + 1);
                break;
            case OCTOBER:
                signGoal.setOctFinish(signGoal.getOctFinish() + 1);
                break;
            case NOVEMBER:
                signGoal.setNovFinish(signGoal.getNovFinish() + 1);
                break;
            case DECEMBER:
                signGoal.setDecFinish(signGoal.getDecFinish() + 1);
                break;
        }
     }
}
