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.AssetCategoryEnum;
import org.sky.scientific.e.AssetStatusEnum;
import org.sky.scientific.excel.XmFixedAssetExcel;
import org.sky.scientific.mapper.AssetMapper;
import org.sky.scientific.mapper.XmFixedAssetMapper;
import org.sky.scientific.mapper.XmMapper;
import org.sky.scientific.mapper.YsZjfyycqdtfyMapper;
import org.sky.scientific.pojo.dto.XmAssetQueryParam;
import org.sky.scientific.pojo.entity.AssetEntity;
import org.sky.scientific.pojo.entity.XmFixedAsset;
import org.sky.scientific.pojo.entity.YsZjfyycqdtfyEntity;
import org.sky.scientific.pojo.vo.XmFixedAssetCostVo;
import org.sky.scientific.service.IXmFixedAssetService;
import org.sky.scientific.service.IXmService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 研发项目固定资产表 服务实现类
 *
 * @author Kd
 * @since 2025-06-29
 */
@Slf4j
@Service
@AllArgsConstructor
public class XmFixedAssetServiceImpl extends BaseServiceImpl<XmFixedAssetMapper, XmFixedAsset> implements IXmFixedAssetService {

	private final YsZjfyycqdtfyMapper ysZjfyycqdtfyMapper;
	private final XmMapper xmMapper;
	private final AssetMapper assetMapper;
	private final IXmService xmService;

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

		return page.setRecords(list);
	}

	@Override
	@Transactional
	public boolean xmFixAsset_zhijieyinyong(String yearAndMonth, AssetCategoryEnum type) {
		if (StringUtil.isBlank(yearAndMonth)) {
			throw new ServiceException("参数yearAndMonth不能为空");
		}
		Date lastDate = DateUtil.minusMonths(DateUtil.parse(yearAndMonth, DateUtil.PATTERN_YYYYMM), 1);
		//获取上个月数据

		List<XmFixedAsset> lastMonthList = baseMapper.selectXmFixedAssetByYearAndMonth(DateUtil.format(lastDate, DateUtil.PATTERN_YYYYMM), type.getCode());
		//获取本月数据
		List<XmFixedAsset> thisMonthList = baseMapper.selectXmFixedAssetByYearAndMonth(yearAndMonth, type.getCode());
		List<String> zcbmList = thisMonthList.stream().map(XmFixedAsset::getZcbm).toList();

		//已结题项目列表
		List<Long> jtXmIdList = new ArrayList<>();
		//待新增的数据
		List<XmFixedAsset> insertList = new ArrayList<>();
		if (!CollectionUtil.isEmpty(lastMonthList)) {
			//复制上个月数据到本月
			for (XmFixedAsset dbAsset : lastMonthList) {
				//dbAsset已存在，则跳过
				if (zcbmList.contains(dbAsset.getZcbm())) {
					continue;
				}
				if (jtXmIdList.contains(dbAsset.getXmId())) {
					continue;
				}
				if (xmService.judgeXmIsOver(dbAsset.getXmId(), false)) {
					jtXmIdList.add(dbAsset.getXmId());
					continue;
				}
				if (dbAsset.getAsset() != null && !Func.equals(dbAsset.getAsset().getStatus(), AssetStatusEnum.正常.getCode())) {
					continue;
				}
				XmFixedAsset asset = new XmFixedAsset();
				asset.setYearAndMonth(yearAndMonth);
				asset.setXmId(dbAsset.getXmId());
				asset.setZcbm(dbAsset.getZcbm());
				asset.setType(type.getCode());
				insertList.add(asset);
			}
		} else {
			//若无，则获取预算表中的资产，研发项目周期（含变更）包含本月的
			List<YsZjfyycqdtfyEntity> ysList = ysZjfyycqdtfyMapper.selectByYearAndMonth(yearAndMonth, type.getCode());
			if (CollectionUtil.isEmpty(ysList)) {
				throw new ServiceException("项目预算表中无数据");
			}
			for (YsZjfyycqdtfyEntity ys : ysList) {
				if (CollectionUtil.isNotEmpty(zcbmList) && zcbmList.contains(ys.getZcbm())) {
					continue;
				}
				if (jtXmIdList.contains(ys.getXmId())) {
					continue;
				}
				if (xmService.judgeXmIsOver(ys.getXmId(), false)) {
					jtXmIdList.add(ys.getXmId());
					continue;
				}
				if (!Func.equals(ys.getAssetStatus(), AssetStatusEnum.正常.getCode())) {
					continue;
				}
				XmFixedAsset asset = new XmFixedAsset();
				asset.setYearAndMonth(yearAndMonth);
				asset.setXmId(ys.getXmId());
				asset.setZcbm(ys.getZcbm());
				asset.setType(type.getCode());
				insertList.add(asset);
			}
		}
		if (CollectionUtil.isEmpty(insertList)) {
			throw new ServiceException("数据已全部引用");
		}
		return this.saveBatch(insertList);
	}

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

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

		List<XmFixedAsset> insertList = new ArrayList<>();
		Map<String, Long> xmIdMap = new HashMap<>();
		Map<String, AssetEntity> assetIdMap = new HashMap<>();
		for (XmFixedAssetExcel excel : data) {
			if (CollectionUtil.isNotEmpty(zcbmList) && zcbmList.contains(excel.getZcbm())) {
				continue;
			}
			if (Func.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.getZcmc(), excel.getZcbm())) {
				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.getZcbm() + "]不存在");
				}
				if (Func.equals(dbAsset.getStatus(), AssetStatusEnum.正常.getCode())) {
					throw new ServiceException("资产[" + excel.getZcbm() + "]的状态非正常");
				}
			}
			assetIdMap.put(assetkey, dbAsset);

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

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

	@Override
	public boolean saveXmFixedAsset(XmFixedAsset xmAsset) {
		if (StringUtil.isBlank(xmAsset.getYearAndMonth())) {
			throw new ServiceException("参数yearAndMonth不能为空");
		}

		xmService.judgeXmIsOver(xmAsset.getXmId(), true);
		//获取本月数据
		List<XmFixedAsset> thisMonthList = baseMapper.selectXmFixedAssetByYearAndMonth(xmAsset.getYearAndMonth(), xmAsset.getType());

		long count = thisMonthList.stream().filter(e -> Objects.equals(e.getXmId(), xmAsset.getXmId()) && Objects.equals(e.getZcbm(), xmAsset.getZcbm())).count();
		if (count > 0) {
			throw new ServiceException("资产已配置到项目中");
		}
		AssetEntity dbAsset = assetMapper.selectByYearAndMonthAndBmOrMc(xmAsset.getYearAndMonth(), xmAsset.getZcbm(), null);
		if (Func.notNull(dbAsset) && !Func.equals(dbAsset.getStatus(), AssetStatusEnum.正常.getCode())) {
			throw new ServiceException("资产状态非正常");
		}
		return this.save(xmAsset);
	}

	@Override
	public IPage<XmFixedAssetCostVo> keyanyiqishebeizhejiufeiyongfenpeibiao(IPage<XmFixedAssetCostVo> page, XmAssetQueryParam dto) {
		if (StringUtil.isBlank(dto.getYearAndMonth())) {
			throw new ServiceException("参数yearAndMonth不能为空");
		}
		dto.setTenantId(SecureUtil.getTenantId());
		List<XmFixedAssetCostVo> list = baseMapper.keyanyiqishebeizhejiufeiyongfenpeibiao(page, dto);
		return page.setRecords(list);
	}

	@SneakyThrows
	@Override
	public void exportKeyanyiqishebeizhejiufeiyongfenpeibiao(OutputStream os, List<XmFixedAssetCostVo> 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("zgs", temp.getAsset().getZgs());
			data.put("workHours", temp.getWorkHours());
			data.put("yanfaFenTanLv", temp.getYanfaFenTanLv());
			if (Func.isNull(temp.getYanfaFenTanLv())) {
				temp.setYanfaFenTanLv(0.00);
			}
			data.put("yanfazhejiu", BigDecimal.valueOf(temp.getYanfaFenTanLv()).multiply(temp.getAsset().getYzje()));
			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();
		}
	}

	@Override
	public IPage<XmFixedAssetCostVo> keyanfangwujianzhuwuzhejiufeiyongfenpeibiao(IPage<XmFixedAssetCostVo> page, XmAssetQueryParam dto) {
		if (StringUtil.isBlank(dto.getYearAndMonth())) {
			throw new ServiceException("参数yearAndMonth不能为空");
		}
		dto.setTenantId(SecureUtil.getTenantId());
		List<XmFixedAssetCostVo> list = baseMapper.keyanfangwujianzhuwuzhejiufeiyongfenpeibiao(page, dto);

		return page.setRecords(list);
	}

	@SneakyThrows
	@Override
	public void exportKeyanfangwujianzhuwuzhejiufeiyongfenpeibiao(OutputStream os, List<XmFixedAssetCostVo> 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());
			AssetEntity asset = temp.getAsset();
			if (Func.isNull(asset)) {
				asset = new AssetEntity();
				asset.setZcyz(BigDecimal.ZERO);
				asset.setYzje(BigDecimal.ZERO);
				asset.setZgs(0.0);
			}
			data.put("zcbm", asset.getZcbm());
			data.put("zcmc", asset.getZcmc());
			data.put("zclb", asset.getZclb());
			data.put("yt", asset.getYt());
			data.put("zcyz", asset.getZcyz());
			data.put("jcz", asset.getJcz());
			data.put("yzje", asset.getYzje());
			data.put("zgs", asset.getZgs());

			data.put("workHours", temp.getWorkHours());
			data.put("yanfaFenTanLv", temp.getYanfaFenTanLv());
			if (Func.isNull(temp.getYanfaFenTanLv())) {
				temp.setYanfaFenTanLv(0.00);
			}
			data.put("yanfazhejiu", BigDecimal.valueOf(temp.getYanfaFenTanLv()).multiply(asset.getYzje()));
			data.put("fenTanLvQueDingYiJu", temp.getFenTanLvQueDingYiJu());
			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();
		}
	}

	@SneakyThrows
	@Override
	public void exportKeyanyiqishebeimingxibiao(HttpServletResponse response, XmAssetQueryParam dto) {
		List<XmFixedAsset> list = this.selectXmFixAssetPage(Condition.getPage(new Query().setCurrent(1).setSize(Integer.MAX_VALUE)), dto, AssetCategoryEnum.仪器设备).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());
			AssetStatusEnum assetStatusEnum = Arrays.stream(AssetStatusEnum.values()).filter(o -> o.getCode() == temp.getAsset().getStatus()).findFirst().orElse(AssetStatusEnum.正常);
			data.put("statusStr", assetStatusEnum.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();
		}
	}

	@SneakyThrows
	@Override
	public void exportFangwujianzhuwu(HttpServletResponse response, XmAssetQueryParam dto) {
		List<XmFixedAsset> list = this.selectXmFixAssetPage(Condition.getPage(new Query().setCurrent(1).setSize(Integer.MAX_VALUE)), dto, AssetCategoryEnum.房屋建筑物).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());
			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 boolean keyanfangwujianzhuwuzhejiufeiyongfenpeibiaoEdit(XmFixedAssetCostVo dto) {
		if (Func.isNull(dto.getId())) {
			throw new ServiceException("id不能为空");
		}
		if (Func.notNull(dto.getYanfaFenTanLv()) && (dto.getYanfaFenTanLv() < 0 || dto.getYanfaFenTanLv() > 1.0)) {
			throw new ServiceException("研发分摊率只能是[0,1]之间");
		}
		XmFixedAsset fixedAsset = new XmFixedAsset();
		fixedAsset.setId(dto.getId());
		fixedAsset.setYanfaFenTanLv(dto.getYanfaFenTanLv());
		fixedAsset.setFenTanLvQueDingYiJu(dto.getFenTanLvQueDingYiJu());
		return baseMapper.updateById(fixedAsset) == 1;
	}
}
