
package org.sky.scientific.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.sky.core.excel.util.ExcelUtil;
import org.sky.core.log.exception.ServiceException;
import org.sky.core.mp.base.BaseServiceImpl;
import org.sky.core.mp.support.Condition;
import org.sky.core.mp.support.Query;
import org.sky.core.secure.utils.SecureUtil;
import org.sky.core.tool.utils.*;
import org.sky.scientific.e.AssetStatusEnum;
import org.sky.scientific.excel.XmIntangibleAssetExcel;
import org.sky.scientific.mapper.AssetMapper;
import org.sky.scientific.mapper.XmIntangibleAssetMapper;
import org.sky.scientific.mapper.XmMapper;
import org.sky.scientific.mapper.YsWxzctxfyMapper;
import org.sky.scientific.pojo.dto.XmAssetQueryParam;
import org.sky.scientific.pojo.entity.AssetEntity;
import org.sky.scientific.pojo.entity.XmIntangibleAsset;
import org.sky.scientific.pojo.vo.XmIntangibleAssetCostVo;
import org.sky.scientific.pojo.vo.YsWxzctxfyVO;
import org.sky.scientific.service.IXmIntangibleAssetService;
import org.sky.scientific.service.IXmService;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 研发项目无形资产表 服务实现类
 *
 * @author Kd
 * @since 2025-06-29
 */
@Slf4j
@Service
@AllArgsConstructor
public class XmIntangibleAssetServiceImpl extends BaseServiceImpl<XmIntangibleAssetMapper, XmIntangibleAsset> implements IXmIntangibleAssetService {

	private final YsWxzctxfyMapper ysWxzctxfyMapper;
	private final XmMapper xmMapper;
	private final AssetMapper assetMapper;
	private final IXmService xmService;

	@Override
	public IPage<XmIntangibleAsset> selectPage(IPage<XmIntangibleAsset> page, XmAssetQueryParam param) {
		if (StringUtil.isBlank(param.getYearAndMonth())) {
			throw new ServiceException("参数yearAndMonth不能为空");
		}
		List<XmIntangibleAsset> list = null;
		if (param.getYearAndMonth().length() == 4) {
			//全年
			list = baseMapper.selectPageByYear(page, param);
		} else {
			//按月
			list = baseMapper.selectPageByYearAndMonth(page, param);
		}

		return page.setRecords(list);
	}

	@Override
	public boolean zhijieyinyong(String yearAndMonth) {
		if (StringUtil.isBlank(yearAndMonth)) {
			throw new ServiceException("参数yearAndMonth不能为空");
		}
		//查询项目周期包含yearAndMonth的项目
		//查询每个项目上个月数据，有则引入，无则引入预算表数据，都没数据，则提示：无数据可引入。否则提示：引入成功

		//获取本月数据
		List<XmIntangibleAsset> thisMonthList = baseMapper.selectListByYearAndMonth(yearAndMonth);

		Date lastDate = DateUtil.minusMonths(DateUtil.parse(yearAndMonth, DateUtil.PATTERN_YYYYMM), 1);
		//获取上个月数据
		List<XmIntangibleAsset> lastMonthList = baseMapper.selectListByYearAndMonth(DateUtil.format(lastDate, DateUtil.PATTERN_YYYYMM));
//		Map<Long, List<String>> map = lastMonthList.stream().collect(Collectors.groupingBy(XmIntangibleAsset::getXmId, Collectors.mapping(XmIntangibleAsset::getZcbm, Collectors.toList())));
		Map<Long, List<XmIntangibleAsset>> c1 = thisMonthList.stream().collect(Collectors.groupingBy(XmIntangibleAsset::getXmId));
		//已结题项目列表
		List<Long> jtXmIdList = new ArrayList<>();
		//待新增的数据
		List<XmIntangibleAsset> insertList = new ArrayList<>();
		if (!CollectionUtil.isEmpty(lastMonthList)) {
			//复制上个月数据到本月
			for (XmIntangibleAsset dbAsset : lastMonthList) {
				//本月为包含dbAsset，新增
				if (Func.isNotEmpty(c1.get(dbAsset.getXmId())) && c1.get(dbAsset.getXmId()).stream().anyMatch(item -> Func.equals(item.getZcbm(), dbAsset.getZcbm()))) {
					continue;
				}
				if (jtXmIdList.contains(dbAsset.getXmId())) {
					continue;
				}
				if (xmService.judgeXmIsOver(dbAsset.getXmId(), false)) {
					jtXmIdList.add(dbAsset.getXmId());
					continue;
				}
				if (!Func.equals(dbAsset.getAsset().getStatus(), AssetStatusEnum.正常.getCode())) {
					continue;
				}
				XmIntangibleAsset asset = new XmIntangibleAsset();
				asset.setYearAndMonth(yearAndMonth);
				asset.setXmId(dbAsset.getXmId());
				asset.setZcbm(dbAsset.getZcbm());
				insertList.add(asset);
			}

		} else {
			//若无，则获取预算表中的无形资产，研发项目周期（含变更）包含本月的
			List<YsWxzctxfyVO> ysList = ysWxzctxfyMapper.selectByYearAndMonth(yearAndMonth);
			if (CollectionUtil.isEmpty(ysList)) {
				throw new ServiceException("项目预算表中没有无形资产");
			}
			for (YsWxzctxfyVO ys : ysList) {
				if (Func.isNotEmpty(c1.get(ys.getXmId())) && c1.get(ys.getXmId()).stream().anyMatch(item -> Func.equals(item.getZcbm(), ys.getZcEntity().getZcbm()))) {
					continue;
				}
				if (jtXmIdList.contains(ys.getXmId())) {
					continue;
				}
				if (xmService.judgeXmIsOver(ys.getXmId(), false)) {
					jtXmIdList.add(ys.getXmId());
					continue;
				}
				if (!Func.equals(ys.getZcEntity().getStatus(), AssetStatusEnum.正常.getCode())) {
					continue;
				}
				XmIntangibleAsset asset = new XmIntangibleAsset();
				asset.setYearAndMonth(yearAndMonth);
				asset.setXmId(ys.getXmId());
				asset.setZcbm(ys.getZcEntity().getZcbm());
				insertList.add(asset);
			}
		}
		if (CollectionUtil.isEmpty(insertList)) {
			throw new ServiceException("数据已全部引用");
		}
		return this.saveBatch(insertList);

	}

	@Override
	public void xmIntangibleAssetImport(MultipartFile file, String yearAndMonth) {
		if (StringUtil.isBlank(yearAndMonth)) {
			throw new ServiceException("参数yearAndMonth不能为空");
		}

		List<XmIntangibleAssetExcel> data = ExcelUtil.read(file, 0, 2, XmIntangibleAssetExcel.class);
		if (CollectionUtil.isEmpty(data)) {
			throw new ServiceException("导入数据为空");
		}
		//获取本月数据
		List<XmIntangibleAsset> thisMonthList = baseMapper.selectListByYearAndMonth(yearAndMonth);
		List<String> zcbmList = thisMonthList.stream().map(XmIntangibleAsset::getZcbm).toList();

		List<XmIntangibleAsset> insertList = new ArrayList<>();
		Map<String, Long> xmIdMap = new HashMap<>();
		Map<String, AssetEntity> assetIdMap = new HashMap<>();
		for (XmIntangibleAssetExcel excel : data) {

			if (zcbmList.contains(excel.getZcbm())) {
				throw new ServiceException("序号为[" + excel.getXh() + "]的资产已存在");
			}
			if (StringUtil.isBlank(excel.getXmbh())) {
				throw new ServiceException("序号为[" + excel.getXh() + "]的项目研发编号为空");
			}
			String xmkey = "xm:" + excel.getXmbh();
			Long xmId = xmIdMap.get(xmkey);
			if (xmId == null) {
				xmId = xmMapper.getXmIdByXmmcOrXmbh(null, null, excel.getXmbh());
				if (xmId == null) {
					throw new ServiceException("序号为[" + excel.getXh() + "]的项目不存在");
				}
				xmService.judgeXmIsOver(xmId, true);
			}
			xmIdMap.put(xmkey, xmId);

			if (StringUtil.isAllBlank(excel.getZcbm(), excel.getZcmc())) {
				throw new ServiceException("序号为[" + excel.getXh() + "]的资产编码和资产名称都为空");
			}

			String assetkey = "asset:" + excel.getZcbm() + ":" + excel.getZcmc();
			AssetEntity dbAsset = assetIdMap.get(assetkey);
			if (dbAsset == null) {
				dbAsset = assetMapper.selectByYearAndMonthAndBmOrMc(yearAndMonth, excel.getZcbm(), excel.getZcmc());
				if (dbAsset == null) {
					throw new ServiceException("序号为[" + excel.getXh() + "]的资产不存在");
				}
			}
			assetIdMap.put(assetkey, dbAsset);

			if (!Func.equals(dbAsset.getStatus(), AssetStatusEnum.正常.getCode())) {
				throw new ServiceException("序号为[" + excel.getXh() + "]的资产状态非正常");
			}

			XmIntangibleAsset xmAsset = new XmIntangibleAsset();
			xmAsset.setYearAndMonth(yearAndMonth);
			xmAsset.setXmId(xmId);
			xmAsset.setZcbm(dbAsset.getZcbm());
			insertList.add(xmAsset);
		}
		if (CollectionUtil.isEmpty(insertList)) {
			throw new ServiceException("数据已存在，导入失败");
		} else {
			this.saveBatch(insertList);
		}
	}

	@Override
	public boolean physicalDeleteByIds(List<Long> ids) {
		for (Long id : ids) {
			XmIntangibleAsset intangibleAsset = baseMapper.selectById(id);
			xmService.judgeXmIsOver(intangibleAsset.getXmId(), true);
		}
		return baseMapper.physicalDeleteByIds(ids);
	}

	@Override
	public boolean saveXmIntangibleAsset(XmIntangibleAsset xmAsset) {
		if (StringUtil.isBlank(xmAsset.getYearAndMonth())) {
			throw new ServiceException("参数yearAndMonth不能为空");
		}
		xmService.judgeXmIsOver(xmAsset.getXmId(), true);

		//获取本月数据
		List<XmIntangibleAsset> thisMonthList = baseMapper.selectListByYearAndMonth(xmAsset.getYearAndMonth());
		List<String> zcbmList = thisMonthList.stream().map(XmIntangibleAsset::getZcbm).toList();

		if (CollectionUtil.isNotEmpty(zcbmList) && zcbmList.contains(xmAsset.getZcbm())) {
			throw new ServiceException("资产已配置到项目中");
		}
		return this.save(xmAsset);
	}

	@Override
	public boolean updateXmIntangibleAsset(XmIntangibleAsset xmAsset) {
		if (null == xmAsset.getId()) {
			throw new ServiceException("参数id不能为空");
		}
		xmService.judgeXmIsOver(xmAsset.getId(), true);
		return this.updateById(xmAsset);
	}

	@SneakyThrows
	@Override
	public void exportKeyanwuxingzichanmingxibiao(HttpServletResponse response, XmAssetQueryParam dto) {
		List<XmIntangibleAsset> list = this.selectPage(Condition.getPage(new Query().setCurrent(1).setSize(Integer.MAX_VALUE)), dto).getRecords();
		AtomicInteger index = new AtomicInteger(1);
		List<JSONObject> results = new ArrayList<>();
		list.forEach(temp -> {
			JSONObject data = new JSONObject();
			data.put("xh", index.getAndIncrement() + "");
			data.put("yearAndMonth", dto.getYearAndMonth());
			data.put("xmbh", temp.getXmbh());
			data.put("xmmc", temp.getXmmc());
			data.put("zcbm", temp.getAsset().getZcbm());
			data.put("zcmc", temp.getAsset().getZcmc());
			data.put("zclb", temp.getAsset().getZclb());
			data.put("gl", temp.getAsset().getGl());
			data.put("yt", temp.getAsset().getYt());
			data.put("kssjStr", Func.notNull(temp.getAsset().getKssj()) ? DateUtil.format(temp.getAsset().getKssj(), DateUtil.PATTERN_DATE) : "");
			data.put("sysm", temp.getAsset().getSysm());
			data.put("ysysm", temp.getAsset().getYsysm());
			data.put("zcyz", temp.getAsset().getZcyz());
			data.put("jcz", temp.getAsset().getJcz());
			data.put("yzje", temp.getAsset().getYzje());
			data.put("userName", temp.getUserName());
			Optional<AssetStatusEnum> optional = Arrays.stream(AssetStatusEnum.values()).filter(o -> o.getCode() == temp.getAsset().getStatus()).findFirst();
			data.put("statusStr", optional.isPresent() ? optional.get().getName() : "");
			results.add(data);
		});

		InputStream templateFileName = this.getClass().getClassLoader().getResourceAsStream("export-template/研发资产管理/每月无形资产明细.xls");
		response.setContentType("application/vnd.ms-excel");
		response.setCharacterEncoding("utf-8");
		response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("每月无形资产明细.xls", Charsets.UTF_8));
		ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
			.withTemplate((templateFileName))
			.excelType(ExcelTypeEnum.XLS)
			.build();

		WriteSheet writeSheet = EasyExcel.writerSheet().build();
		FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
		//设置list集合数据
		excelWriter.fill(results, fillConfig, writeSheet);
		Map<String, Object> map = new HashMap<>();
		String yearAndMonth = dto.getYearAndMonth();
		map.put("yearAndMonth", yearAndMonth.length() == 6 ? yearAndMonth.substring(0, 4) + "年" + yearAndMonth.substring(5) + "月" : dto.getYearAndMonth() + "年");
		excelWriter.fill(map, writeSheet);
		excelWriter.finish();
		if (templateFileName != null) {
			templateFileName.close();
		}
	}

	@Override
	public IPage<XmIntangibleAssetCostVo> keyanwuxingzichantanxiaofeiyongfenpeibiao(IPage<XmIntangibleAssetCostVo> page, XmAssetQueryParam dto) {

		if (StringUtil.isBlank(dto.getYearAndMonth())) {
			throw new ServiceException("参数yearAndMonth不能为空");
		}
		dto.setTenantId(SecureUtil.getTenantId());
		List<XmIntangibleAssetCostVo> list = baseMapper.keyanwuxingzichantanxiaofeiyongfenpeibiao(page, dto);
		for (XmIntangibleAssetCostVo vo : list) {
			AssetEntity asset = vo.getAsset();
			//研发分摊率=月研发工时/月总工时
			if (vo.getAttendanceHours() == 0 || vo.getWorkHours() == 0) {
				vo.setYanfaFenTanLv(0);
			} else {
				vo.setYanfaFenTanLv(vo.getWorkHours() / vo.getAttendanceHours());
			}
			//研发摊销=(月折旧额/月摊销额（元）) * 研发分摊率
			vo.setYanfaTanXiao(asset != null ? asset.getYzje().doubleValue() * vo.getYanfaFenTanLv() : 0.0);
		}
		return page.setRecords(list);
	}

	@SneakyThrows
	@Override
	public void exportKeyanwuxingzichanfenpeibiao(OutputStream os, List<XmIntangibleAssetCostVo> list, String yearAndMonth) {
		AtomicInteger index = new AtomicInteger(1);
		List<JSONObject> results = new ArrayList<>();
		list.forEach(temp -> {
			JSONObject data = new JSONObject();
			data.put("xh", index.getAndIncrement() + "");
			data.put("yearAndMonth", yearAndMonth);
			data.put("xmbh", temp.getXmbh());
			data.put("xmmc", temp.getXmmc());
			data.put("zcbm", temp.getAsset().getZcbm());
			data.put("zcmc", temp.getAsset().getZcmc());
			data.put("zclb", temp.getAsset().getZclb());
			data.put("yt", temp.getAsset().getYt());
			data.put("zcyz", temp.getAsset().getZcyz());
			data.put("jcz", temp.getAsset().getJcz());
			data.put("yzje", temp.getAsset().getYzje());
			data.put("attendanceHours", temp.getAttendanceHours());
			data.put("workHours", temp.getWorkHours());
			data.put("yanfaFenTanLv", temp.getYanfaFenTanLv());
			data.put("yanfaTanXiao", temp.getYanfaTanXiao());
			results.add(data);
		});
		InputStream templateFileName = this.getClass().getClassLoader().getResourceAsStream("export-template/研发费用管理/无形资产摊销费用/无形资产摊销费用分配表.xls");
		ExcelWriter excelWriter = EasyExcel.write(os)
			.withTemplate((templateFileName))
			.excelType(ExcelTypeEnum.XLS)
			.build();
		WriteSheet writeSheet = EasyExcel.writerSheet().build();
		FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
		//设置list集合数据
		excelWriter.fill(results, fillConfig, writeSheet);
		Map<String, Object> map = new HashMap<>();
		map.put("yearAndMonth", yearAndMonth);
		excelWriter.fill(map, writeSheet);
		excelWriter.finish();
		if (templateFileName != null) {
			templateFileName.close();
		}
	}
}
