/**
 * BladeX Commercial License Agreement
 * Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
 * <p>
 * Use of this software is governed by the Commercial License Agreement
 * obtained after purchasing a license from BladeX.
 * <p>
 * 1. This software is for development use only under a valid license
 * from BladeX.
 * <p>
 * 2. Redistribution of this software's source code to any third party
 * without a commercial license is strictly prohibited.
 * <p>
 * 3. Licensees may copyright their own code but cannot use segments
 * from this software for such purposes. Copyright of this software
 * remains with BladeX.
 * <p>
 * Using this software signifies agreement to this License, and the software
 * must not be used for illegal purposes.
 * <p>
 * THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
 * not liable for any claims arising from secondary or illegal development.
 * <p>
 * Author: Chill Zhuang (bladejava@qq.com)
 */
package org.springblade.zhaocai.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.AllArgsConstructor;
import org.springblade.core.mp.base.BaseServiceImpl;
import org.springblade.core.tool.utils.Func;
import org.springblade.zhaocai.mapper.ProcurementPlanMapper;
import org.springblade.zhaocai.pojo.entity.ProcurementPlan;
import org.springblade.zhaocai.pojo.entity.ProcurementPlanDetail;
import org.springblade.zhaocai.pojo.entity.ProcurementPlanMaterial;
import org.springblade.zhaocai.pojo.vo.ProcurementPlanDetailVO;
import org.springblade.zhaocai.pojo.vo.ProcurementPlanMaterialVO;
import org.springblade.zhaocai.pojo.vo.ProcurementPlanVO;
import org.springblade.zhaocai.service.IBillCodeService;
import org.springblade.zhaocai.service.IProcurementPlanDetailService;
import org.springblade.zhaocai.service.IProcurementPlanMaterialService;
import org.springblade.zhaocai.service.IProcurementPlanService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 年度招采计划服务实现类
 *
 * @author Chill
 */
@Service
@AllArgsConstructor
public class ProcurementPlanServiceImpl extends BaseServiceImpl<ProcurementPlanMapper, ProcurementPlan> implements IProcurementPlanService {

	private final IProcurementPlanDetailService procurementPlanDetailService;
	private final IProcurementPlanMaterialService procurementPlanMaterialService;
	private final IBillCodeService billCodeService;

	@Override
	public IPage<ProcurementPlan> selectProcurementPlanPage(IPage<ProcurementPlan> page, ProcurementPlan procurementPlan) {
		return page.setRecords(baseMapper.selectProcurementPlanPage(page, procurementPlan));
	}

	@Override
	public ProcurementPlanVO detail(Long id) {
		ProcurementPlanVO vo = new ProcurementPlanVO();
		ProcurementPlan plan = baseMapper.selectById(id);
		if (plan == null) {
			return vo;
		}
		Func.copy(plan, vo);
		List<ProcurementPlanDetail> detailList = procurementPlanDetailService.listByPlanId(id);
		vo.setDetailList(detailList.stream().map(detail -> {
			ProcurementPlanDetailVO detailVO = new ProcurementPlanDetailVO();
			Func.copy(detail, detailVO);
			List<ProcurementPlanMaterial> materialList = procurementPlanMaterialService.listByProjectId(detail.getId());
			detailVO.setMaterialList(materialList.stream().map(material -> {
				ProcurementPlanMaterialVO materialVO = new ProcurementPlanMaterialVO();
				Func.copy(material, materialVO);
				return materialVO;
			}).collect(Collectors.toList()));
			return detailVO;
		}).collect(Collectors.toList()));
		return vo;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean submit(ProcurementPlanVO procurementPlanVO) {
		// 提交状态
		procurementPlanVO.setFlowStatus("SUBMITTED");
		boolean result = this.saveProcurementPlan(procurementPlanVO);

		// TODO: 接入 blade-flow 流程引擎
		// R<BladeFlow> result = flowClient.startProcessInstanceById(
		//     processDefinitionId,
		//     FlowUtil.getBusinessKey("zc_procurement_plan", String.valueOf(planId)),
		//     variables
		// );

		return result;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public boolean saveDraft(ProcurementPlanVO procurementPlanVO) {
		// 草稿状态
		procurementPlanVO.setFlowStatus("DRAFT");
		return this.saveProcurementPlan(procurementPlanVO);
	}

	/**
	 * 公共保存逻辑（提交和草稿复用）
	 */
	private boolean saveProcurementPlan(ProcurementPlanVO procurementPlanVO) {
		// 新建时生成单据号
		if (procurementPlanVO.getId() == null && !StringUtils.hasText(procurementPlanVO.getBillNo())) {
			String billNo = billCodeService.generateBillCode("PROCUREMENT_PLAN"	,"NDZC");
			procurementPlanVO.setBillNo(billNo);
		}

		// 自动计算项目属性、招标方式、主表金额
		this.calculateDetail(procurementPlanVO);

		// 保存主表
		boolean result = saveOrUpdate(procurementPlanVO);
		Long planId = procurementPlanVO.getId();

		// 删除旧项目明细和物料明细
		procurementPlanDetailService.removeByPlanId(planId);
		procurementPlanMaterialService.removeByPlanId(planId);

		// 保存项目明细及物料明细
		List<ProcurementPlanDetailVO> detailVOList = procurementPlanVO.getDetailList();
		if (Func.isNotEmpty(detailVOList)) {
			for (int i = 0; i < detailVOList.size(); i++) {
				ProcurementPlanDetailVO detailVO = detailVOList.get(i);
				ProcurementPlanDetail detail = new ProcurementPlanDetail();
				Func.copy(detailVO, detail);
				detail.setPlanId(planId);
				detail.setSortNo(i + 1);
				procurementPlanDetailService.save(detail);
				Long detailId = detail.getId();

				// 保存物料明细
				List<ProcurementPlanMaterialVO> materialVOList = detailVO.getMaterialList();
				if (Func.isNotEmpty(materialVOList)) {
					List<ProcurementPlanMaterial> materialList = new ArrayList<>();
					for (int j = 0; j < materialVOList.size(); j++) {
						ProcurementPlanMaterialVO materialVO = materialVOList.get(j);
						ProcurementPlanMaterial material = new ProcurementPlanMaterial();
						Func.copy(materialVO, material);
						material.setPlanId(planId);
						material.setProjectId(detailId);
						material.setSortNo(j + 1);
						materialList.add(material);
					}
					procurementPlanMaterialService.saveBatch(materialList);
					// 冗余汇总
					detail.setMaterialDetail(buildMaterialSummary(materialList));
					procurementPlanDetailService.updateById(detail);
				}
			}
		}

		return result;
	}

	/**
	 * 计算项目明细的项目属性、招标方式，并汇总主表金额
	 */
	private void calculateDetail(ProcurementPlanVO procurementPlanVO) {
		List<ProcurementPlanDetailVO> detailVOList = procurementPlanVO.getDetailList();
		BigDecimal totalAmount = BigDecimal.ZERO;
		if (Func.isNotEmpty(detailVOList)) {
			for (ProcurementPlanDetailVO detailVO : detailVOList) {
				String projectType = detailVO.getProjectType();
				BigDecimal budgetAmount = detailVO.getBudgetAmount() == null ? BigDecimal.ZERO : detailVO.getBudgetAmount();
				String projectAttr = calculateProjectAttr(projectType, budgetAmount);
				String biddingMethod = calculateBiddingMethod(projectType, budgetAmount);
				detailVO.setProjectAttr(projectAttr);
				detailVO.setBiddingMethod(biddingMethod);
				totalAmount = totalAmount.add(budgetAmount);
			}
		}
		procurementPlanVO.setEstimatedAmount(totalAmount);
		procurementPlanVO.setAmountUpper(digitUppercase(totalAmount));
	}

	/**
	 * 计算项目属性
	 */
	private String calculateProjectAttr(String projectType, BigDecimal budgetAmount) {
		boolean isEngineering = "工程类".equals(projectType);
		if ((isEngineering && budgetAmount.compareTo(new BigDecimal("100")) >= 0)
			|| (!isEngineering && budgetAmount.compareTo(new BigDecimal("50")) >= 0)) {
			return "一类项目";
		}
		if ((isEngineering && budgetAmount.compareTo(new BigDecimal("50")) >= 0)
			|| (!isEngineering && budgetAmount.compareTo(new BigDecimal("10")) >= 0)) {
			return "二类项目";
		}
		return "三类项目";
	}

	/**
	 * 计算招标方式
	 */
	private String calculateBiddingMethod(String projectType, BigDecimal budgetAmount) {
		String projectAttr = calculateProjectAttr(projectType, budgetAmount);
		if ("一类项目".equals(projectAttr) || "二类项目".equals(projectAttr)) {
			return "招标";
		}
		return "比价";
	}

	/**
	 * 构建物料明细冗余汇总
	 */
	private String buildMaterialSummary(List<ProcurementPlanMaterial> materialList) {
		return materialList.stream()
			.map(material -> material.getMaterialName() + " x " + material.getQuantity())
			.collect(Collectors.joining(", "));
	}

	/**
	 * 金额大写转换
	 */
	private String digitUppercase(BigDecimal amount) {
		if (amount == null || amount.compareTo(BigDecimal.ZERO) == 0) {
			return "零元整";
		}
		String[] fraction = {"角", "分"};
		String[] digit = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
		String[][] unit = {{"元", "万", "亿"}, {"", "拾", "佰", "仟"}};
		double n = amount.doubleValue();
		String head = n < 0 ? "欠" : "";
		n = Math.abs(n);
		StringBuilder s = new StringBuilder();
		for (int i = 0; i < fraction.length; i++) {
			s.append((digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("零.", ""));
		}
		if (s.length() == 0) {
			s.append("整");
		}
		n = Math.floor(n);
		for (int i = 0; i < unit[0].length && n > 0; i++) {
			StringBuilder p = new StringBuilder();
			for (int j = 0; j < unit[1].length && n > 0; j++) {
				p.insert(0, digit[(int) (n % 10)] + unit[1][j]);
				n = Math.floor(n / 10);
			}
			s.insert(0, p.toString().replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i]);
		}
		return head + s.toString()
			.replaceAll("(零.)*零元", "元")
			.replaceAll("(零.)+", "零")
			.replaceAll("^整$", "零元整");
	}

}
