
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.FillWrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.servlet.http.HttpServletResponse;
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.AssetExcel;
import org.sky.scientific.mapper.AssetMapper;
import org.sky.scientific.pojo.dto.AssetDTO;
import org.sky.scientific.pojo.dto.CostSummaryDTO;
import org.sky.scientific.pojo.dto.XmAssetCostQueryParam;
import org.sky.scientific.pojo.entity.AssetEntity;
import org.sky.scientific.pojo.vo.AssetVO;
import org.sky.scientific.pojo.vo.CostSummaryVO;
import org.sky.scientific.pojo.vo.XmAssetCostSummary;
import org.sky.scientific.service.IAssetService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 资产表 服务实现类
 *
 * @author Kd
 * @since 2025-06-29
 */
@Slf4j
@Service
public class AssetServiceImpl extends BaseServiceImpl<AssetMapper, AssetEntity> implements IAssetService {

	@Override
	public IPage<AssetVO> selectAssetPage(IPage<AssetVO> page, AssetDTO dto) {
		if(Func.isNotBlank(dto.getZclb())){
			dto.setZclbList(Arrays.asList(dto.getZclb().split(",")));
		}
		return page.setRecords(baseMapper.selectAssetPage(page, dto));
	}

	@Override
	public boolean saveAsset(AssetEntity asset) {
		if (StringUtil.isBlank(asset.getYearAndMonth())) {
			throw new ServiceException("参数yearAndMonth不能为空");
		}
		LambdaQueryWrapper<AssetEntity> qw = Wrappers.<AssetEntity>lambdaQuery().eq(AssetEntity::getZcbm, asset.getZcbm()).eq(AssetEntity::getYearAndMonth, asset.getYearAndMonth());
		if (this.baseMapper.selectCount(qw) > 0) {
			throw new ServiceException("资产【" + asset.getZcbm() + "】已存在");
		}

		if(!isFixedAsset(asset.getZclb())){
			asset.setGl("/");
		}

		//使用寿命-已使用月份数=0时，即已足额折旧
//			仪器设置的算法：当前时间为2025年01月-2024年5月，差额为9个月，因为折旧从次月开始，所以已使用月数为8个月（即9-1=8），再将使用寿命-已使用月份数=0时，即已足额折旧。
//			无形资产：当月即摊销，不需要-1

		long ysysm = cn.hutool.core.date.DateUtil.betweenMonth(DateUtil.parse(asset.getYearAndMonth(), DateUtil.PATTERN_YYYYMM) , asset.getKssj(), false);
//			这里
		if (!isFixedAsset(asset.getZclb())) {
			ysysm++;
		}
		asset.setYsysm((int) ysysm);
		asset.setStatus((asset.getSysm() - asset.getYsysm() <= 0) ? 2 : 0);
		return this.save(asset);
	}

	@Override
	public void importAsset(MultipartFile file, String yearAndMonth) {

		List<AssetExcel> data = ExcelUtil.read(file, 0, 2, AssetExcel.class);

		for (AssetExcel excel : data) {
			AssetEntity zc = Objects.requireNonNull(BeanUtil.copyProperties(excel, AssetDTO.class));

			zc.setYearAndMonth(yearAndMonth);
			//yearAndMonth 是否存在该物资
			LambdaQueryWrapper<AssetEntity> queryWrapper = Wrappers.lambdaQuery();
			queryWrapper.eq(AssetEntity::getZcbm, excel.getZcbm());
			queryWrapper.eq(AssetEntity::getYearAndMonth, yearAndMonth);
			if (this.count(queryWrapper) > 0) {
				throw new ServiceException("资产编号【" + excel.getZcbm() + "】已存在");
			}

			if(Func.notNull(zc.getJcz())){
				zc.setJcz(Math.min(zc.getJcz() / 100.0, 1.0));
			}
			int status = AssetStatusEnum.valueOf(excel.getStatusName()).getCode();
			zc.setStatus(status);
			this.save(zc);
		}
	}

	@Transactional
	@Override
	public boolean fetchLastMonthData(AssetDTO zc) {
		//查询上个月的数据
		//得到上个月的年月
		String lastDate = DateUtil.format(DateUtil.minusMonths(DateUtil.parse(zc.getYearAndMonth(), DateUtil.PATTERN_YYYYMM), 1), DateUtil.PATTERN_YYYYMM);
		LambdaQueryWrapper<AssetEntity> queryWrapper = Wrappers.<AssetEntity>lambdaQuery().eq(AssetEntity::getYearAndMonth, lastDate);
		List<AssetEntity> lastMonthDataList = this.baseMapper.selectList(queryWrapper);
		if (CollectionUtil.isEmpty(lastMonthDataList)) {
			throw new ServiceException("上个月资产数据为空");
		}
		//与本月数据对比，去重后保存至数据库
		for (AssetEntity temp : lastMonthDataList) {
			LambdaQueryWrapper<AssetEntity> qw = Wrappers.<AssetEntity>lambdaQuery().eq(AssetEntity::getZcbm, temp.getZcbm()).eq(AssetEntity::getYearAndMonth, zc.getYearAndMonth());
			if (this.baseMapper.selectCount(qw) > 0) {
				throw new ServiceException("资产【" + temp.getZcbm() + "】已存在");
			}
			temp.setYearAndMonth(zc.getYearAndMonth());
			if (Func.equals(temp.getStatus(), AssetStatusEnum.正常.getCode())) {
				temp.setYsysm(Func.toInt(temp.getYsysm(), 0) + 1);
				//使用寿命-已使用月份数=0时，即已足额折旧
				if (temp.getSysm() - temp.getYsysm() <= 0) {
					temp.setStatus(AssetStatusEnum.已足额折旧.getCode());
				}
			}
			temp.setId(null);
			this.save(temp);
		}
		return true;
	}

	@Override
	public List<AssetEntity> selectAssetList() {
		return baseMapper.selectAssetList();
	}

	@Override
	public boolean physicalDeleteByIds(List<Long> ids) {
		//删除说明
		//①　删除：如果此资产，在研发项目中，已使用情况下，不可以删除。系统提示：资产已被使用，无法删除！
		//②　如果此资产，无任何研发项目使用，可以在资产清单管理中，将此资产进行删除。
		//③　如果此资产，曾经被研发项目使用（可能研发项目后续不再使用此资产），这一类情况也不可以进行删除。
		List<Long> list = baseMapper.checkAssetUsage(ids);
		if(Func.isNotEmpty(list)){
			throw new ServiceException("资产已被使用，无法删除！");
		}
		return baseMapper.physicalDeleteByIds(ids);
	}

	@SneakyThrows
	@Override
	public void exportAsset(HttpServletResponse response, AssetDTO dto) {

		Query query = new Query().setCurrent(1).setSize(Integer.MAX_VALUE);
		List<AssetVO> assetVOList = this.selectAssetPage(Condition.getPage(query), dto).getRecords();

		AtomicInteger i = new AtomicInteger(1);
		assetVOList.forEach(temp -> {
 			temp.setXh(i.getAndIncrement());
		});

		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();
		//设置list集合数据
		excelWriter.fill(new FillWrapper("list", assetVOList), writeSheet);
		excelWriter.finish();
		if (templateFileName != null) {
			templateFileName.close();
		}
	}

	@Override
	public IPage<XmAssetCostSummary> zjCqdtWxzctxFyHzb(IPage<XmAssetCostSummary> page, XmAssetCostQueryParam dto) {
		if (Func.isBlank(dto.getYearAndMonth())) {
			throw new ServiceException("参数yearAndMonth不能为空");
		}
		List<XmAssetCostSummary> list = null;
		dto.setTenantId(SecureUtil.getTenantId());
		if (dto.getYearAndMonth().length() == 6) {
			list = baseMapper.zjCqdtWxzctxFyHzbByYearAndMonth(page, dto);
		} else if (dto.getYearAndMonth().length() == 4) {
			list = baseMapper.zjCqdtWxzctxFyHzbByYear(page, dto);
		} else {
			throw new ServiceException("参数yearAndMonth格式错误，yyyyMM或yyyy");
		}

		for (XmAssetCostSummary vo : list) {
			vo.setTotal(vo.getYqsbzjfy() + vo.getFwzjfy() + vo.getCqdtfy() + vo.getWxzcdtfy());
		}
		return page.setRecords(list);
	}

	@Override
	public List<CostSummaryVO> costSummary(CostSummaryDTO dto) {
		if (Func.isBlank(dto.getYearAndMonth())) {
			throw new ServiceException("参数yearAndMonth不能为空");
		}

		String startYearMonth = dto.getYearAndMonth().substring(0, 4) + "01";
		dto.setStartYearMonth(startYearMonth);
		dto.setMonthCount(Integer.parseInt(dto.getYearAndMonth().substring(4)));
		dto.setTenantId(SecureUtil.getTenantId());
		List<CostSummaryVO> list = baseMapper.costSummary(dto);
		for (CostSummaryVO vo : list) {

			vo.setWwfyAdjust(vo.getWwfy().multiply(new BigDecimal("0.8")).setScale(2, RoundingMode.HALF_UP));

			vo.setTotal(vo.getRyrgfy().add(vo.getZjtrfy()).add(vo.getZjfyycqdtfy()).add(vo.getSjfy()).add(vo.getWxzctxfy()).add(vo.getZbtsfyysyfy()).add(vo.getQtfy()).add(vo.getWwfyAdjust()).setScale(2, RoundingMode.HALF_UP));

		}
		return list;
	}

	@Override
	public boolean updateAsset(AssetEntity asset) {
		if (Func.isNull(asset.getId())) {
			throw new ServiceException("参数id不能为空");
		}
		LambdaQueryWrapper<AssetEntity> qw = Wrappers.<AssetEntity>lambdaQuery().eq(AssetEntity::getZcbm, asset.getZcbm()).eq(AssetEntity::getYearAndMonth, asset.getYearAndMonth());
		AssetEntity dbAsset = this.getOne(qw);
		if (Func.isNull(dbAsset)) {
			throw new ServiceException("资产不存在");
		}
		if (Func.equals(dbAsset.getZcbm(), asset.getZcbm()) && !Func.equals(dbAsset.getId(), asset.getId())) {
			throw new ServiceException("资产【" + asset.getZcbm() + "】已存在");
		}

		if(!isFixedAsset(asset.getZclb())){
			asset.setGl("/");
		}
//		正常状态、停用状态，可修改资产数据。其他情况不能修改。假设在修改资产时，正好出现使用寿命-已使用月份数=0时，即已足额折旧状态时，就显示为已足额折旧状态了，不可以再次修改了。
//		修改资产时，系统需要二次确认。


		if (Func.equals(dbAsset.getStatus(), AssetStatusEnum.正常.getCode()) || Func.equals(dbAsset.getStatus(), AssetStatusEnum.停用.getCode())) {
//			if (Func.isNull(asset.getYsysm())) {
				//使用寿命-已使用月份数=0时，即已足额折旧
//			仪器设置的算法：当前时间为2025年01月-2024年5月，差额为9个月，因为折旧从次月开始，所以已使用月数为8个月（即9-1=8），再将使用寿命-已使用月份数=0时，即已足额折旧。
//			无形资产：当月即摊销，不需要-1
				long ysysm = cn.hutool.core.date.DateUtil.betweenMonth(DateUtil.parse(asset.getYearAndMonth(), DateUtil.PATTERN_YYYYMM), asset.getKssj(), false);
//			这里
				if (!Func.equals("仪器设备", asset.getZclb())) {
					ysysm++;
				}
				asset.setYsysm((int) ysysm);
			}
			if (asset.getSysm() - asset.getYsysm() <= 0) {
				asset.setStatus(AssetStatusEnum.已足额折旧.getCode());
			}
//		}
		return this.updateById(asset);
	}

	@Override
	public boolean updateStatus(AssetEntity asset) {
		if (asset.getId() == null) {
			throw new ServiceException("参数assetId不能为空");
		}
		if (Func.isNull(asset.getStatus())) {
			throw new ServiceException("参数status不能为空");
		}
		AssetEntity dbAsset = baseMapper.selectById(asset.getId());
		if (Func.isNull(dbAsset)) {
			throw new ServiceException("资产不存在");
		}

		if (asset.getStatus() == AssetStatusEnum.改造.getCode() && !isFixedAsset(dbAsset.getZclb())) {
			throw new ServiceException("只有固定资产才能改造");
		}
//		String name = AssetStatusEnum.改造.name();
//		①　正常状态：表示正常使用中；正常折旧，已使用寿命/月数累加。可进行“改造”、“停用”、“资产处置”。
//		②　停用状态：表示停止使用状态；虽然停用，但是正常折旧，已使用寿命/月数继续累加。停用后，可点击“恢复”恢复为正常状态。可进行“改造”、“资产处置”。
//		③　改造状态：表示改造中，改造期已使用寿命/月数/折旧为“全部暂停”状态。改造完成，需点击“恢复按钮”，恢复时需对资产内容进行修改完成。恢复为正常状态。
//		④　已足额折扣状态：按照使用寿命，全部折旧完毕；不可以进行操作；后续不再提折旧。不再使用，不再显示。
//		⑤　资产处理状态：表示资产已被转让、报废、捐赠或其他处理等；不可以进行操作；后续不属于企业 ，不再计提折旧，不能再使用。
//		⑥　/：表示无操作
//		⑦　注意，资产总表涉及资产明细统计，需进行相应的处理
		if (Func.equals(dbAsset.getStatus(), AssetStatusEnum.已足额折旧.getCode())) {
			throw new ServiceException("该资产已足额折旧");
		}
		if (Func.equals(dbAsset.getStatus(), AssetStatusEnum.资产处置.getCode())) {
			throw new ServiceException("该资产已处置");
		}
//		if (Func.equals(AssetStatusEnum.正常.getCode(), dbAsset.getStatus())) {
//			//①　正常状态：表示正常使用中；正常折旧，已使用寿命/月数累加。可进行“改造”、“停用”、“资产处置”。
//			if (!Arrays.asList(AssetStatusEnum.改造.getCode(), AssetStatusEnum.停用.getCode(), AssetStatusEnum.资产处置.getCode()).contains(asset.getStatus())) {
//				throw new ServiceException("状态为正常的资产，可进行改造、停用、资产处置操作");
//			}
//		} else if (Func.equals(AssetStatusEnum.停用.getCode(), dbAsset.getStatus())) {
//			//②　停用状态：表示停止使用状态；虽然停用，但是正常折旧，已使用寿命/月数继续累加。停用后，可点击“恢复”恢复为正常状态。可进行“改造”、“资产处置”。
//			if (!Arrays.asList(AssetStatusEnum.改造.getCode(), AssetStatusEnum.资产处置.getCode(), AssetStatusEnum.正常.getCode()).contains(asset.getStatus())) {
//				throw new ServiceException("状态为停用的资产，可进行改造、恢复、资产处置操作");
//			}
//		} else if (Func.equals(AssetStatusEnum.改造.getCode(), dbAsset.getStatus())) {
//			//改造状态：表示改造中，改造期已使用寿命/月数/折旧为“全部暂停”状态。改造完成，需点击“恢复按钮”，恢复时需对资产内容进行修改完成。恢复为正常状态。
//			if (!List.of(AssetStatusEnum.正常.getCode()).contains(asset.getStatus())) {
//				throw new ServiceException("状态为改造的资产，可进行恢复操作");
//			}
//		}

		return baseMapper.updateStatus(asset.getId(), asset.getStatus()) == 1;
	}

	@Override
	public boolean recover(AssetEntity asset) {

		if(Func.isNull(asset.getId())){
			throw new ServiceException("参数id不能为空");
		}
//		if (!List.of(AssetStatusEnum.改造.getCode(), AssetStatusEnum.停用.getCode()).contains(asset.getStatus())) {
//			throw new ServiceException("状态为改造/停用的资产，可进行恢复操作");
//		}

		asset.setStatus(AssetStatusEnum.正常.getCode());
		if (Func.isNull(asset.getYsysm())) {
			//使用寿命-已使用月份数=0时，即已足额折旧
//			仪器设置的算法：当前时间为2025年01月-2024年5月，差额为9个月，因为折旧从次月开始，所以已使用月数为8个月（即9-1=8），再将使用寿命-已使用月份数=0时，即已足额折旧。
//			无形资产：当月即摊销，不需要-1
			long ysysm = cn.hutool.core.date.DateUtil.betweenMonth(cn.hutool.core.date.DateUtil.date(), asset.getKssj(), false);
//			这里
			if (!isFixedAsset(asset.getZclb())) {
				ysysm++;
			}
			asset.setYsysm((int) ysysm);
		}
		if (asset.getSysm() - asset.getYsysm() <= 0) {
			asset.setStatus(AssetStatusEnum.已足额折旧.getCode());
		}
		return this.updateById(asset);
	}

	public static boolean isFixedAsset(String zclb) {
		return List.of("仪器设备", "房屋建筑物").contains(zclb);
	}
}
