package com.yifu.cloud.plus.v1.yifu.insurances.service.insurance.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.alibaba.excel.util.ListUtils;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
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.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;
import com.yifu.cloud.plus.v1.yifu.common.core.util.ErrorMessage;
import com.yifu.cloud.plus.v1.yifu.common.core.util.ExcelUtil;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
import com.yifu.cloud.plus.v1.yifu.common.core.vo.YifuUser;
import com.yifu.cloud.plus.v1.yifu.common.security.util.SecurityUtils;
import com.yifu.cloud.plus.v1.yifu.insurances.entity.*;
import com.yifu.cloud.plus.v1.yifu.insurances.mapper.insurances.TInsuranceCompanyMapper;
import com.yifu.cloud.plus.v1.yifu.insurances.mapper.insurances.TInsurancePolicyMapper;
import com.yifu.cloud.plus.v1.yifu.insurances.mapper.insurances.TInsuranceTypeMapper;
import com.yifu.cloud.plus.v1.yifu.insurances.service.insurance.TBusinessOperateService;
import com.yifu.cloud.plus.v1.yifu.insurances.service.insurance.TInsuranceDetailService;
import com.yifu.cloud.plus.v1.yifu.insurances.service.insurance.TInsurancePolicyService;
import com.yifu.cloud.plus.v1.yifu.insurances.util.BeanCopyUtils;
import com.yifu.cloud.plus.v1.yifu.insurances.util.LocalDateUtil;
import com.yifu.cloud.plus.v1.yifu.insurances.vo.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.InputStream;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @author licancan
 * @description 针对表【t_insurance_policy(保单号对应起止时间表)】的数据库操作Service实现
 * @date 2022-12-07 16:40:16
 */
@Log4j2
@RequiredArgsConstructor
@Service
public class TInsurancePolicyServiceImpl extends ServiceImpl<TInsurancePolicyMapper, TInsurancePolicy> implements TInsurancePolicyService {
	@Resource
	private TBusinessOperateService tBusinessOperateService;
	@Resource
	@Lazy
	private TInsuranceDetailService tInsuranceDetailService;

	@Autowired
	private TInsuranceCompanyMapper companyMapper;

	@Autowired
	private TInsuranceTypeMapper typeMapper;

	/**
	 * 保单号对应起止保时间分页查询
	 *
	 * @param page            分页对象
	 * @param param 查询参数
	 * @return {@link IPage <TInsurancePolicy>}
	 * @author licancan
	 */
	@Override
	public IPage<TInsurancePolicy> pageDiy(Page page, InsurancePolicyListParam param) {
		IPage<TInsurancePolicy> list = this.baseMapper.getInsurancePolicyListPage(page, param);
		// 购买月数
		if (CollectionUtils.isNotEmpty(list.getRecords())){
			list.getRecords().stream().forEach(e ->{
				e.setBuyMonth(LocalDateUtil.betweenMonth(e.getPolicyStart().toString(),e.getPolicyEnd().toString()));
			});
		}
		return list;
	}

	/**
	 * 保单号对应起止保时间列表（不分页）
	 *
	 * @param param
	 * @return {@link List<TInsurancePolicy>}
	 * @author licancan
	 */
	@Override
	public List<TInsurancePolicy> getInsurancePolicyList(InsurancePolicyListParam param) {
		List<TInsurancePolicy> list = this.baseMapper.getInsurancePolicyList(param);
		return list;
	}

	/**
	 * 通过id查询详情
	 *
	 * @param id
	 * @return {@link R<TInsurancePolicyDetailVO>}
	 * @author licancan
	 */
	@Override
	public R<TInsurancePolicyDetailVO> getDetailById(String id) {
		if(Common.isEmpty(id)){
			return R.failed("id不能为空");
		}
		TInsurancePolicy byId = getById(id);
		if (!Optional.ofNullable(byId).isPresent()){
			return R.failed("数据不存在");
		}
		TInsurancePolicyDetailVO vo = new TInsurancePolicyDetailVO();
		BeanCopyUtils.copyProperties(byId,vo);
		List<TBusinessOperate> list = tBusinessOperateService.getOperateListByBusinessId(id);
		if (CollectionUtils.isNotEmpty(list)){
			vo.setOperateList(list);
		}
		return R.ok(vo);
	}

	/**
	 * 新增，内部调用的，保证调用方把该传的字段都传了（保单号、起止保时间、保险公司、险种）
	 *
	 * @param policy
	 * @return {@link R}
	 * @author licancan
	 */
	@Override
	public R saveTInsurancePolicy(TInsurancePolicy policy) {
		if (StringUtils.isNotEmpty(policy.getPolicyNo())){
			TInsurancePolicy one = this.getOne(Wrappers.<TInsurancePolicy>query().lambda()
					.eq(TInsurancePolicy::getPolicyNo, policy.getPolicyNo())
					.eq(TInsurancePolicy::getDeleteFlag,CommonConstants.ZERO_INT)
					.last(CommonConstants.LAST_ONE_SQL));
			if (!Optional.ofNullable(one).isPresent()){
				this.save(policy);

				//第一次新增插入变更记录表为insert，前端会将insert渲染为批量导入
				TBusinessOperate operate = new TBusinessOperate();
				operate.setBusinessId(policy.getId());
				operate.setDifferenceInfo("insert");
				tBusinessOperateService.save(operate);
			}
		}
		return R.ok();
	}

	/**
	 * 修改保单号对应起止保时间
	 *
	 * @param param
	 * @return {@link R}
	 * @author licancan
	 */
	@Override
	@Transactional(value = "insurancesTransactionManager" ,rollbackFor = {Exception.class})
	public R updateInsurancePolicy(InsurancePolicyListEditParam param) {
		TInsurancePolicy tInsurancePolicy = this.baseMapper.selectById(param.getId());
		if (!Optional.ofNullable(tInsurancePolicy).isPresent()){
			return R.failed("数据不存在");
		}
		if (!param.getPolicyNo().equals(tInsurancePolicy.getPolicyNo())){
			return R.failed("保单号不能修改");
		}
		//操作日志
		tBusinessOperateService.saveModificationRecord(param.getId(),tInsurancePolicy,param,null);
		BeanCopyUtils.copyProperties(param,tInsurancePolicy);
		updateById(tInsurancePolicy);
		return R.ok();
	}

	/**
	 * 删除保单号对应起止保时间
	 *
	 * @param id 主键
	 * @return {@link R}
	 * @author licancan
	 */
	@Override
	public R deleteInsurancePolicy(String id) {
		if(Common.isEmpty(id)){
			return R.failed("id不能为空");
		}
		TInsurancePolicy byId = getById(id);
		if (!Optional.ofNullable(byId).isPresent()){
			return R.failed("数据不存在");
		}
		//检验保单号是否被使用，被使用不能删除
		TInsuranceDetail one = tInsuranceDetailService.getOne(Wrappers.<TInsuranceDetail>query().lambda()
				.eq(TInsuranceDetail::getPolicyNo, byId.getPolicyNo())
				.eq(TInsuranceDetail::getDeleteFlag,CommonConstants.ZERO_INT)
				.last(CommonConstants.LAST_ONE_SQL));
		if (Optional.ofNullable(one).isPresent()){
			return R.failed("存在正常关联的承保信息，禁止删除！");
		}
		LambdaUpdateWrapper<TInsurancePolicy> updateWrapper = new LambdaUpdateWrapper<>();
		updateWrapper.eq(TInsurancePolicy::getId,id)
				.set(TInsurancePolicy::getDeleteFlag, CommonConstants.ONE_INT);
		update(updateWrapper);
		return R.ok();
	}

	@Override
	public R<List<ErrorMessage>> importInsurancePolicy(InputStream inputStream) {
		YifuUser user = SecurityUtils.getUser();
		if (Common.isEmpty(user)) {
			R.failed(CommonConstants.USER_FAIL);
		}
		List<ErrorMessage> errorMessageList = new ArrayList<>();
		ExcelUtil<InsurancePolicyImportVo> util1 = new ExcelUtil<>(InsurancePolicyImportVo.class);
		Map<String, String> policyNoMap = new HashMap<>();
		// 获取所有的保险公司
		Map<String, TInsuranceCompany> companyMap = getCompanyMap();
		// 获取所有险种
		Map<String, TInsuranceType> typeMap = getTypeMap();
		// 匿名内部类 不用额外写一个DemoDataListener
		// 这里 需要指定读用哪个class去读，然后读取第一个sheet 文件流会自动关闭
		try {
			EasyExcel.read(inputStream, InsurancePolicyImportVo.class, new ReadListener<InsurancePolicyImportVo>() {
				/**
				 * 单次缓存的数据量
				 */
				public static final int BATCH_COUNT = CommonConstants.BATCH_COUNT;
				/**
				 *临时存储
				 */
				private List<InsurancePolicyImportVo> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);

				@Override
				public void invoke(InsurancePolicyImportVo data, AnalysisContext context) {
					ReadRowHolder readRowHolder = context.readRowHolder();
					Integer rowIndex = readRowHolder.getRowIndex();
					data.setRowIndex(rowIndex + 1);
					ErrorMessage errorMessage = util1.checkEntity(data, data.getRowIndex());
					if (Common.isNotNull(errorMessage)) {
						errorMessage.setData(data);
						errorMessageList.add(errorMessage);
					} else {
						cachedDataList.add(data);
					}
					if (cachedDataList.size() >= BATCH_COUNT) {
						saveData();
						// 存储完成清理 list
						cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
					}
				}

				@Override
				public void doAfterAllAnalysed(AnalysisContext context) {
					saveData();
				}

				/**
				 * 加上存储数据库
				 */
				private void saveData() {
					log.info("{}条数据，开始存储数据库！", cachedDataList.size());
					importInsurancePolicy(cachedDataList, errorMessageList, user,  policyNoMap,companyMap,typeMap);
					log.info("存储数据库成功！");
				}
			}).sheet().doRead();
			// 把errorMessageList 按 rowIndex 升序
			errorMessageList.sort(Comparator.comparingInt(ErrorMessage::getLineNum));
		} catch (Exception e) {
			log.error(CommonConstants.IMPORT_DATA_ANALYSIS_ERROR, e);
			return R.failed(CommonConstants.IMPORT_DATA_ANALYSIS_ERROR);
		} finally {
			Common.clear(policyNoMap);
			Common.clear(companyMap);
			Common.clear(typeMap);
		}
		return Common.judgeAllMessage(errorMessageList);
	}

	public void importInsurancePolicy(List<InsurancePolicyImportVo> excelVOList,
									List<ErrorMessage> errorMessageList,
									YifuUser user, Map<String, String> policyNoMap,
									  Map<String, TInsuranceCompany> companyMap,
									  Map<String, TInsuranceType> typeMap) {
		if (!Common.isNotNull(excelVOList)) {
			return;
		}
		//获取本次导入对应的保单号是否已经存在
		Map<String, String> existMap =  getExistMap(excelVOList);
		InsurancePolicyImportVo excel = null;
		TInsuranceCompany company = null;
		TInsuranceType type = null;
		TBusinessOperate operate = null;
		TInsurancePolicy policy = null;
		// 执行数据插入操作 组装
		for (int i = 0; i < excelVOList.size(); i++) {

			excel = excelVOList.get(i);
			// 判断保单号是否重复
			if (policyNoMap.get(excel.getPolicyNo()) != null) {
				errorMessageList.add(new ErrorMessage(excel.getRowIndex(), "保单号【" + excel.getPolicyNo() + "】与第" + policyNoMap.get(excel.getPolicyNo()) + "行重复，未导入",excel));
				continue;
			}
			if (existMap.get(excel.getPolicyNo()) != null){
				errorMessageList.add(new ErrorMessage(excel.getRowIndex(), "保单号【" + excel.getPolicyNo() + "】已存在，未导入",excel));
				continue;
			}
			company = companyMap.get(excel.getInsuranceCompanyName());
			if (null == company){
				errorMessageList.add(new ErrorMessage(excel.getRowIndex(), "保单号【" + excel.getPolicyNo() + "】的保险公司名称未找到，未导入",excel));
				continue;
			}
			type = typeMap.get(excel.getInsuranceTypeName());
			if (null == type){
				errorMessageList.add(new ErrorMessage(excel.getRowIndex(), "保单号【" + excel.getPolicyNo() + "】的险种名称未找到，未导入",excel));
				continue;
			}
			if (!type.getInsuranceCompanyId().equals(company.getId())){
				errorMessageList.add(new ErrorMessage(excel.getRowIndex(), "保单号【" + excel.getPolicyNo() + "】的险种与保险公司不一致，未导入",excel));
				continue;
			}
			if (LocalDateUtil.parseLocalDate(excel.getPolicyStart()) == null){
				errorMessageList.add(new ErrorMessage(excel.getRowIndex(), "保单号【" + excel.getPolicyNo() + "】的保单开始时间格式错误，未导入",excel));
				continue;
			}
			if (LocalDateUtil.parseLocalDate(excel.getPolicyEnd()) == null){
				errorMessageList.add(new ErrorMessage(excel.getRowIndex(), "保单号【" + excel.getPolicyNo() + "】的保单截止时间格式错误，未导入",excel));
				continue;
			}
			policy = new TInsurancePolicy();
			policy.setPolicyNo(excel.getPolicyNo());
			policy.setInsuranceCompanyName(excel.getInsuranceCompanyName());
			policy.setInsuranceTypeName(excel.getInsuranceTypeName());
			policy.setPolicyStart(LocalDateUtil.parseLocalDate(excel.getPolicyStart()));
			policy.setPolicyEnd(LocalDateUtil.parseLocalDate(excel.getPolicyEnd()));
			policy.setCreateBy(user.getId());
			policy.setUpdateBy(user.getId());
			policy.setEnableFlag(CommonConstants.ZERO_INT);
			policy.setDeleteFlag(CommonConstants.ZERO_INT);
			//插入保单维护信息
			baseMapper.insert(policy);
			//插入保单维护操作日志
			//第一次新增插入变更记录表为insert，前端会将insert渲染为批量导入
			operate = new TBusinessOperate();
			operate.setBusinessId(policy.getId());
			operate.setDifferenceInfo("insert");
			tBusinessOperateService.save(operate);
			policyNoMap.put(excel.getPolicyNo(), excel.getRowIndex().toString());

		}
		// 清理map list 等数据
		Common.clear(excelVOList);
	}

	private Map<String, String> getExistMap(List<InsurancePolicyImportVo> excelVOList) {
		Map<String, String> existMap = null;
		List<String> existNos;
		if (Common.isNotNull(excelVOList)){
			existNos = excelVOList.stream().map(InsurancePolicyImportVo::getPolicyNo).collect(Collectors.toList());
			List<TInsurancePolicy> policies = this.baseMapper.selectList(Wrappers.<TInsurancePolicy>query().lambda()
					.in(TInsurancePolicy::getPolicyNo,existNos).eq(TInsurancePolicy::getDeleteFlag,CommonConstants.ZERO_INT));
			if (Common.isNotNull(policies)) {
				existMap = policies.stream().collect(Collectors.toMap(TInsurancePolicy::getPolicyNo, TInsurancePolicy::getId,(v1, v2) -> v1));
			}
		}
		if (!Common.isNotNull(existMap)){
			existMap = new HashMap<>();
		}
		return existMap;
	}

	/**
	 * @Author fxj
	 * @Description 获取所有险种,缓存起来,缓存起来，排除删除的、险种名称是空的
	 * @Date 17:17 2025/8/29
	 * @Param
	 * @return
	**/
	private Map<String, TInsuranceType> getTypeMap() {
		List<TInsuranceType> companyList = typeMapper.selectList(Wrappers.<TInsuranceType>query().lambda()
				.isNotNull(TInsuranceType::getName)
				.eq(TInsuranceType::getDeleteFlag, CommonConstants.ZERO_INT));
		if (Common.isEmpty(companyList)) {
			return new HashMap<>();
		}
		return companyList.stream()
				.collect(Collectors.toMap(TInsuranceType::getName,
						v -> v, (existing, replacement) -> existing // 处理重复key的情况
				));
	}

	/**
	 * @Author fxj
	 * @Description 查询所有保险公司，缓存起来，排除删除的、保险公司名称是空的
	 * @Date 17:17 2025/8/29
	 * @Param
	 * @return
	**/
	private Map<String, TInsuranceCompany> getCompanyMap() {
		List<TInsuranceCompany> companyList = companyMapper.selectList(Wrappers.<TInsuranceCompany>query().lambda()
				.isNotNull(TInsuranceCompany::getCompanyName)
				.eq(TInsuranceCompany::getDeleteFlag, CommonConstants.ZERO_INT));
		if (Common.isEmpty(companyList)) {
			return new HashMap<>();
		}
		return companyList.stream()
				.collect(Collectors.toMap(TInsuranceCompany::getCompanyName,
					v -> v, (existing, replacement) -> existing // 处理重复key的情况
				));
	}


	@Override
	public Page<PolicyListVo> policyPageToAutoSelect(Page<PolicyListVo> page, InsuredParam param, String mId) {
		// 查保单未过期的数据
		String today = LocalDateUtil.getDateSrt(LocalDate.now());
		param.setPolicyEnd(today);
		return baseMapper.policyPageToAutoSelect(page,param);
	}
}






