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.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.sky.core.excel.util.ExcelUtil;
import org.sky.core.log.exception.ServiceException;
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.node.ForestNodeMerger;
import org.sky.core.tool.utils.BeanUtil;
import org.sky.core.tool.utils.Charsets;
import org.sky.core.tool.utils.CollectionUtil;
import org.sky.core.tool.utils.Func;
import org.sky.scientific.excel.SubjectEnterpriseExcel;
import org.sky.scientific.mapper.SubjectEnterpriseMapper;
import org.sky.scientific.mapper.SubjectMapper;
import org.sky.scientific.mapper.XmCostDetailsMapper;
import org.sky.scientific.pojo.dto.SubjectQueryDto;
import org.sky.scientific.pojo.entity.Subject;
import org.sky.scientific.pojo.entity.SubjectEnterprise;
import org.sky.scientific.pojo.entity.XmCostDetailsEntity;
import org.sky.scientific.pojo.vo.SubjectVO;
import org.sky.scientific.service.ISubjectService;
import org.sky.scientific.utils.ExportUtil;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 服务实现类
 */
@Service
@AllArgsConstructor
public class SubjectServiceImpl extends ServiceImpl<SubjectMapper, Subject> implements ISubjectService {

	private final static String PARENT_ID = "parentId";

	private final SubjectEnterpriseMapper subjectEnterpriseMapper;
	private final XmCostDetailsMapper xmCostDetailsMapper;

	@Override
	public List<SubjectVO> lazyList(SubjectQueryDto subject) {
		List<SubjectVO> list = baseMapper.lazyList(SecureUtil.getTenantId(), subject);
		return ForestNodeMerger.merge(list);
	}

	@Override
	public IPage<SubjectEnterprise> selectSubjectEnterpriseList(IPage<SubjectEnterprise> page, SubjectEnterprise subjectEnterprise) {
		subjectEnterprise.setTenantId(SecureUtil.getTenantId());
		return page.setRecords(subjectEnterpriseMapper.selectSubjectEnterpriseList(page, subjectEnterprise));
	}

	@Override
	public boolean submitSubject(Subject subject) {
		subject.setTenantId(SecureUtil.getTenantId());
		Subject dbByName = baseMapper.getByName(subject.getName(), subject.getParentId(), SecureUtil.getTenantId());
		if (Func.isEmpty(subject.getId())) {
			//新增
			if (dbByName != null) {
				throw new ServiceException("科目名称已存在");
			}
			//企业新增的系统科目
			subject.setType(0);
			String maxCode = baseMapper.getMaxCode(subject.getParentId(), SecureUtil.getTenantId());
			subject.setCode(String.valueOf(Long.parseLong(maxCode) + 1));
			return save(subject);
		} else {
			//修改
			if (dbByName != null && !subject.getId().equals(dbByName.getId())) {
				throw new ServiceException("科目名称已存在");
			}
			return updateById(subject);
		}
	}

	@Override
	public boolean deleteSubject(Long subjectId) {
		//查询是否有子项
		if (baseMapper.selectCount(Wrappers.<Subject>lambdaQuery().eq(Subject::getParentId, subjectId)) > 0) {
			throw new ServiceException("请先删除子项！");
		}
		//企业会计科目中是否有引用该科目
		if (subjectEnterpriseMapper.selectCount(Wrappers.<SubjectEnterprise>lambdaQuery().eq(SubjectEnterprise::getSubjectId, subjectId)) > 0) {
			throw new ServiceException("企业会计科目设置中引用了该科目，请先删除对应的企业会计科目");
		}
		return baseMapper.deleteSubject(subjectId);
	}

	@Override
	public boolean importSubjectEnterprise(MultipartFile file) {
		List<SubjectEnterpriseExcel> data = ExcelUtil.read(file, 0, 2, SubjectEnterpriseExcel.class);
		if (CollectionUtil.isEmpty(data)) {
			throw new ServiceException("未能从模板中读取数据，请检查模板格式是否正确");
		}
		List<SubjectEnterprise> insertList = new ArrayList<>();
		int batchCount = 20;
		for (SubjectEnterpriseExcel excel : data) {
			SubjectEnterprise entity = Objects.requireNonNull(BeanUtil.copyProperties(excel, SubjectEnterprise.class));
			entity.setTenantId(SecureUtil.getTenantId());
			if (subjectEnterpriseMapper.selectCount(Wrappers.<SubjectEnterprise>lambdaQuery().eq(SubjectEnterprise::getCode, excel.getCode())) > 0) {
				throw new ServiceException("企业会计科目代码[" + excel.getCode() + "]已存在");
			}
			Subject dbSubject = baseMapper.selectOne(Wrappers.<Subject>lambdaQuery().eq(Subject::getAccSubject, excel.getSubjectName()));
			if (dbSubject == null) {
				throw new ServiceException("对应会计科目：" + excel.getSubjectName() + "不存在");
			}
			entity.setSubjectId(dbSubject.getId());
			insertList.add(entity);
			if (insertList.size() % batchCount == 0) {
				if (subjectEnterpriseMapper.insertBatch(insertList) > 0) {
					insertList.clear();
				}
			}
		}
		if (Func.isNotEmpty(insertList)) {
			subjectEnterpriseMapper.insertBatch(insertList);
		}
		return true;
	}

	@Override
	public boolean deleteSubjectEnterprise(Long id) {
		if (xmCostDetailsMapper.selectCount(Wrappers.<XmCostDetailsEntity>lambdaQuery().eq(XmCostDetailsEntity::getESubjectId, id)) > 0) {
			throw new ServiceException("企业研发支出明细账中引用了该科目，无法删除");
		}
		return subjectEnterpriseMapper.deleteById(id) > 0;
	}


	@SneakyThrows
	@Override
	public void exportSubject(HttpServletResponse response, SubjectQueryDto dto) {

		List<SubjectVO> list = this.lazyList(dto);
		if (Func.isEmpty(list)) {
			ExportUtil.processWithNoData(response);
		} else {
			List<JSONObject> resultList = new ArrayList<>();
			traverseSubjectTree(list.get(0), null, null, null, null, 1, resultList);

			AtomicInteger index = new AtomicInteger(1);
			for (JSONObject obj : resultList) {
				obj.put("xh", index.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("系统预设会计科目.xlsx", Charsets.UTF_8));
			ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream())
				.withTemplate((templateFileName))
				.excelType(ExcelTypeEnum.XLS)
				.build();

			WriteSheet writeSheet = EasyExcel.writerSheet().build();
			//设置list集合数据
			excelWriter.fill(resultList, writeSheet);
			excelWriter.finish();
			if (templateFileName != null) {
				templateFileName.close();
			}
		}
	}

	private static void traverseSubjectTree(SubjectVO currentNode, String l1, String l2, String l3, String l4, int currentLevel, List<JSONObject> result) {
		if (currentNode == null) {
			return;
		}

		// 更新各级名称
		String newL1 = l1;
		String newL2 = l2;
		String newL3 = l3;
		String newL4 = l4;

		switch (currentLevel) {
			case 1: // 一级科目
				newL1 = currentNode.getName();
				break;
			case 2: // 二级科目
				newL2 = currentNode.getName();
				break;
			case 3: // 三级科目
				newL3 = currentNode.getName();
				break;
			case 4: // 四级科目
				newL4 = currentNode.getName();
				break;
		}

		// 将当前节点信息添加到结果集
		JSONObject node = new JSONObject();
		node.put("l1", newL1);
		node.put("l2", newL2);
		node.put("l3", newL3);
		node.put("l4", newL4);
		List<String> nameList = new ArrayList<>();
		if (Func.isNotEmpty(newL1)) nameList.add(newL1);
		if (Func.isNotEmpty(newL2)) nameList.add(newL2);
		if (Func.isNotEmpty(newL3)) nameList.add(newL3);
		if (Func.isNotEmpty(newL4)) nameList.add(newL4);
		node.put("code", currentNode.getCode());
		if (currentLevel == 4 && Func.isNotEmpty(nameList)) {
			node.put("name", String.join("\\", nameList));
		} else {
			node.put("name", null);
		}
		node.put("adSubject", currentNode.getAdSubjectEnable() == 1 ? node.get("name") : null);
		node.put("rdSubject", currentNode.getRdSubjectEnable() == 1 ? node.get("name") : null);

		result.add(node);

		// 递归处理子节点
		if (currentNode.getChildren() != null && !currentNode.getChildren().isEmpty()) {
			for (SubjectVO child : currentNode.getChildren()) {
				traverseSubjectTree(child, newL1, newL2, newL3, newL4, currentLevel + 1, result);
			}
		}
	}

	@SneakyThrows
	@Override
	public void exportSubjectEnterprise(HttpServletResponse response, SubjectEnterprise dto) {

		List<SubjectEnterprise> list = this.selectSubjectEnterpriseList(Condition.getPage(new Query().setCurrent(1).setSize(Integer.MAX_VALUE)), dto).getRecords();

		AtomicInteger index = new AtomicInteger(1);
		List<JSONObject> results = new ArrayList<>();
		for (SubjectEnterprise temp : list) {
			JSONObject obj = new JSONObject();
			obj.put("xh", index.getAndIncrement() + "");
			obj.put("code", temp.getCode());
			obj.put("name", temp.getName());
			obj.put("subjectName", temp.getSubjectName());
			obj.put("rdSubject", (Func.notNull(temp.getRdSubjectEnable()) && temp.getRdSubjectEnable() == 1) ? temp.getSubjectName() : "");
			obj.put("adSubject", (Func.notNull(temp.getAdSubjectEnable()) && temp.getAdSubjectEnable() == 1) ? temp.getSubjectName() : "");
			results.add(obj);
		}

		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(results, writeSheet);
		excelWriter.finish();
		if (templateFileName != null) {
			templateFileName.close();
		}
	}

	@Override
	public boolean submitSubjectEnterprise(SubjectEnterprise subjectEnterprise) {
		List<SubjectEnterprise> dbListByCode = subjectEnterpriseMapper.selectList(Wrappers.<SubjectEnterprise>lambdaQuery()
			.eq(SubjectEnterprise::getCode, subjectEnterprise.getCode()));

		if (Func.isNull(subjectEnterprise.getId())) {
			//新增
			if (Func.isNotEmpty(dbListByCode) && Func.equals(dbListByCode.get(0).getCode(), subjectEnterprise.getCode())) {
				throw new ServiceException("科目代码已存在");
			}
			subjectEnterprise.setTenantId(SecureUtil.getTenantId());
			return subjectEnterpriseMapper.insert(subjectEnterprise) == 1;
		} else {
			if (Func.isNotEmpty(dbListByCode) && Func.equals(dbListByCode.get(0).getCode(), subjectEnterprise.getCode()) && !Func.equals(dbListByCode.get(0).getId(), subjectEnterprise.getId())) {
				throw new ServiceException("科目代码已存在");
			}
			subjectEnterprise.setTenantId(SecureUtil.getTenantId());
			return subjectEnterpriseMapper.updateById(subjectEnterprise) == 1;
		}
	}

}
