package com.xunhong.erp.turbo.biz.infrastructure.gateway;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xunhong.erp.turbo.api.biz.dto.cmd.*;
import com.xunhong.erp.turbo.api.biz.dto.enums.AuditStateEnum;
import com.xunhong.erp.turbo.api.biz.dto.enums.AuditSubjectTypeEnum;
import com.xunhong.erp.turbo.api.biz.dto.enums.AuditTypeEnum;
import com.xunhong.erp.turbo.api.biz.dto.qry.AuditPageQry;
import com.xunhong.erp.turbo.api.biz.dto.qry.AuditShowQry;
import com.xunhong.erp.turbo.api.biz.exception.BizErrorCode;
import com.xunhong.erp.turbo.api.biz.exception.BizException;
import com.xunhong.erp.turbo.biz.domain.entity.Audit;
import com.xunhong.erp.turbo.biz.domain.gateway.AuditGateway;
import com.xunhong.erp.turbo.biz.infrastructure.convert.AuditConvert;
import com.xunhong.erp.turbo.biz.infrastructure.entity.AuditDO;
import com.xunhong.erp.turbo.biz.infrastructure.entity.OrderDO;
import com.xunhong.erp.turbo.biz.infrastructure.mapper.AuditMapper;
import com.xunhong.erp.turbo.biz.infrastructure.mapper.OrderMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author shenyifei
 */
@Repository
@RequiredArgsConstructor
public class AuditGatewayImpl implements AuditGateway {
	private final AuditMapper auditMapper;
	private final AuditConvert auditConvert;

	private final OrderMapper orderMapper;

	@Override
	public IPage<Audit> page(AuditPageQry auditPageQry) {
		LambdaQueryWrapper<AuditDO> queryWrapper = Wrappers.lambdaQuery(AuditDO.class);

		queryWrapper.eq(Objects.nonNull(auditPageQry.getAuditId()), AuditDO::getAuditId, auditPageQry.getAuditId());
		queryWrapper.eq(Objects.nonNull(auditPageQry.getType()), AuditDO::getType, auditPageQry.getType());
		queryWrapper.eq(Objects.nonNull(auditPageQry.getState()), AuditDO::getState, auditPageQry.getState());
		queryWrapper.eq(Objects.nonNull(auditPageQry.getSubjectType()), AuditDO::getSubjectType, auditPageQry.getSubjectType());

		queryWrapper.orderByDesc(AuditDO::getCreatedAt);

		IPage<AuditDO> page = new Page<>(auditPageQry.getPageIndex(), auditPageQry.getPageSize());
		page = auditMapper.selectPage(page, queryWrapper);
		Set<Long> orderIdList = page.getRecords().stream().filter(auditDO -> auditDO.getSubjectType().equals(AuditSubjectTypeEnum.PURCHASE_ORDER)).map(AuditDO::getSubjectId).collect(Collectors.toSet());
		if (CollUtil.isNotEmpty(orderIdList)) {
			List<OrderDO> orderDOList = orderMapper.selectByOrderIdList(orderIdList);
			Map<Long, OrderDO> orderDOMap = orderDOList.stream().collect(Collectors.toMap(OrderDO::getOrderId, Function.identity()));
			page.getRecords().forEach(auditDO -> {
				OrderDO orderDO = orderDOMap.get(auditDO.getSubjectId());
				auditDO.setOrderDO(orderDO);
			});
		}

		return page.convert(auditConvert::toAudit);
	}

	@Override
	public Audit update(AuditUpdateCmd auditUpdateCmd) {
		LambdaQueryWrapper<AuditDO> queryWrapper = Wrappers.lambdaQuery(AuditDO.class);
		queryWrapper.eq(AuditDO::getAuditId, auditUpdateCmd.getAuditId());
		queryWrapper.last("limit 1");

		AuditDO auditDO = auditMapper.selectOne(queryWrapper);

		auditConvert.toAuditDO(auditDO, auditUpdateCmd);
		auditMapper.updateById(auditDO);

		return auditConvert.toAudit(auditDO);
	}

	@Override
	public Audit show(AuditShowQry auditShowQry) {
		LambdaQueryWrapper<AuditDO> queryWrapper = Wrappers.lambdaQuery(AuditDO.class);
		queryWrapper.eq(AuditDO::getAuditId, auditShowQry.getAuditId());
		queryWrapper.last("limit 1");

		AuditDO auditDO = auditMapper.selectOne(queryWrapper);
		if (Objects.nonNull(auditDO)) {
			if (auditDO.getSubjectType().equals(AuditSubjectTypeEnum.PURCHASE_ORDER)) {
				OrderDO orderDO = orderMapper.selectByOrderId(auditDO.getSubjectId());
				auditDO.setOrderDO(orderDO);
			}
		}
		return auditConvert.toAudit(auditDO);
	}

	@Override
	public Audit submitReview(OrderSubmitReviewCmd orderSubmitReviewCmd) {
		LambdaQueryWrapper<AuditDO> auditQueryWrapper = Wrappers.lambdaQuery(AuditDO.class);
		auditQueryWrapper.eq(AuditDO::getSubjectId, orderSubmitReviewCmd.getOrderId());
		auditQueryWrapper.eq(AuditDO::getSubjectType, AuditSubjectTypeEnum.PURCHASE_ORDER);
		auditQueryWrapper.eq(AuditDO::getType, AuditTypeEnum.REVIEWER_AUDIT);
		auditQueryWrapper.last("limit 1");
		AuditDO auditDO = auditMapper.selectOne(auditQueryWrapper);

		if (Objects.isNull(auditDO)) {
			auditDO = new AuditDO();
			auditDO.setSubjectId(orderSubmitReviewCmd.getOrderId());
			auditDO.setSubjectType(AuditSubjectTypeEnum.PURCHASE_ORDER);
			auditDO.setType(AuditTypeEnum.REVIEWER_AUDIT);
			auditDO.setState(AuditStateEnum.WAITING_AUDIT);
			auditDO.setCreatedBy(orderSubmitReviewCmd.getCreatedBy());
			auditDO.setCreatedByName(orderSubmitReviewCmd.getCreatedByName());
			auditMapper.insert(auditDO);
		} else {
			auditDO.setState(AuditStateEnum.WAITING_AUDIT);
			auditMapper.updateById(auditDO);
		}

		return auditConvert.toAudit(auditDO);
	}

	@Override
	public Audit withdrawReview(OrderWithdrawReviewCmd orderWithdrawReviewCmd) {
		// 更新审核记录状态为草稿（撤回审核）
		LambdaQueryWrapper<AuditDO> auditQueryWrapper = Wrappers.lambdaQuery(AuditDO.class);
		auditQueryWrapper.eq(AuditDO::getSubjectId, orderWithdrawReviewCmd.getOrderId());
		auditQueryWrapper.eq(AuditDO::getSubjectType, AuditSubjectTypeEnum.PURCHASE_ORDER);
		auditQueryWrapper.eq(AuditDO::getState, AuditStateEnum.WAITING_AUDIT);
		auditQueryWrapper.eq(AuditDO::getType, AuditTypeEnum.REVIEWER_AUDIT);
		auditQueryWrapper.last("limit 1");
		AuditDO auditDO = auditMapper.selectOne(auditQueryWrapper);

		if (auditDO != null) {
			auditDO.setState(AuditStateEnum.AUDIT_CANCEL);
			auditDO.setAuditAt(LocalDateTime.now());
			auditDO.setAuditBy(orderWithdrawReviewCmd.getCreatedBy());
			auditDO.setAuditByName(orderWithdrawReviewCmd.getCreatedByName());
			auditMapper.updateById(auditDO);
		}
		return auditConvert.toAudit(auditDO);
	}

	@Override
	public Audit rejectApprove(OrderRejectApproveCmd orderRejectApproveCmd) {
		// 更新审核记录
		LambdaQueryWrapper<AuditDO> auditQueryWrapper = Wrappers.lambdaQuery(AuditDO.class);
		auditQueryWrapper.eq(AuditDO::getAuditId, orderRejectApproveCmd.getAuditId());
		auditQueryWrapper.eq(AuditDO::getSubjectId, orderRejectApproveCmd.getOrderId());
		auditQueryWrapper.eq(AuditDO::getSubjectType, AuditSubjectTypeEnum.PURCHASE_ORDER);
		auditQueryWrapper.eq(AuditDO::getState, AuditStateEnum.WAITING_AUDIT);
		auditQueryWrapper.eq(AuditDO::getType, AuditTypeEnum.REVIEWER_AUDIT);
		auditQueryWrapper.last("limit 1");
		AuditDO auditDO = auditMapper.selectOne(auditQueryWrapper);

		if (auditDO != null) {
			auditDO.setState(AuditStateEnum.AUDIT_REJECTED);
			auditDO.setAuditReason(orderRejectApproveCmd.getRejectReason());
			auditDO.setAuditAt(LocalDateTime.now());
			auditDO.setAuditBy(orderRejectApproveCmd.getCreatedBy());
			auditDO.setAuditByName(orderRejectApproveCmd.getCreatedByName());
			auditMapper.updateById(auditDO);
		} else {
			// 如果审核记录不存在，抛出异常
			throw new BizException(BizErrorCode.B_BIZ_AUDIT_NOT_FOUND);
		}
		return auditConvert.toAudit(auditDO);
	}

	@Override
	public Audit finalApprove(OrderFinalApproveCmd orderFinalApproveCmd) {
		// 更新审核记录为审核成功
		LambdaQueryWrapper<AuditDO> auditQueryWrapper = Wrappers.lambdaQuery(AuditDO.class);
		auditQueryWrapper.eq(AuditDO::getSubjectId, orderFinalApproveCmd.getOrderId());
		auditQueryWrapper.eq(AuditDO::getSubjectType, AuditSubjectTypeEnum.PURCHASE_ORDER);
		auditQueryWrapper.eq(AuditDO::getState, AuditStateEnum.WAITING_AUDIT);
		auditQueryWrapper.eq(AuditDO::getType, AuditTypeEnum.BOSS_AUDIT);
		auditQueryWrapper.eq(AuditDO::getAuditId, orderFinalApproveCmd.getAuditId());
		auditQueryWrapper.last("limit 1");
		AuditDO auditDO = auditMapper.selectOne(auditQueryWrapper);

		if (auditDO != null) {
			auditDO.setState(AuditStateEnum.AUDIT_SUCCESS);
			auditDO.setAuditAt(LocalDateTime.now());
			auditDO.setAuditBy(orderFinalApproveCmd.getCreatedBy());
			auditDO.setAuditByName(orderFinalApproveCmd.getCreatedByName());
			auditMapper.updateById(auditDO);
		} else {
			// 如果审核记录不存在，抛出异常
			throw new BizException(BizErrorCode.B_BIZ_AUDIT_NOT_FOUND);
		}
		return auditConvert.toAudit(auditDO);
	}

	@Override
	public Audit rejectFinal(OrderRejectFinalCmd orderRejectFinalCmd) {
		// 更新审核记录
		LambdaQueryWrapper<AuditDO> auditQueryWrapper = Wrappers.lambdaQuery(AuditDO.class);
		auditQueryWrapper.eq(AuditDO::getSubjectId, orderRejectFinalCmd.getOrderId());
		auditQueryWrapper.eq(AuditDO::getSubjectType, AuditSubjectTypeEnum.PURCHASE_ORDER);
		auditQueryWrapper.eq(AuditDO::getState, AuditStateEnum.WAITING_AUDIT);
		auditQueryWrapper.eq(AuditDO::getType, AuditTypeEnum.BOSS_AUDIT);
		auditQueryWrapper.eq(AuditDO::getAuditId, orderRejectFinalCmd.getAuditId());
		auditQueryWrapper.last("limit 1");
		AuditDO auditDO = auditMapper.selectOne(auditQueryWrapper);

		if (auditDO != null) {
			auditDO.setState(AuditStateEnum.AUDIT_REJECTED);
			auditDO.setAuditReason(orderRejectFinalCmd.getRejectReason());
			auditDO.setAuditAt(LocalDateTime.now());
			auditDO.setAuditBy(orderRejectFinalCmd.getCreatedBy());
			auditDO.setAuditByName(orderRejectFinalCmd.getCreatedByName());
			auditMapper.updateById(auditDO);
		} else {
			// 如果审核记录不存在，抛出异常
			throw new BizException(BizErrorCode.B_BIZ_AUDIT_NOT_FOUND);
		}
		return auditConvert.toAudit(auditDO);
	}

	@Override
	public Audit approve(OrderApproveCmd orderApproveCmd) {
		// 更新审核记录状态为审核成功
		LambdaQueryWrapper<AuditDO> auditQueryWrapper = Wrappers.lambdaQuery(AuditDO.class);
		auditQueryWrapper.eq(AuditDO::getSubjectId, orderApproveCmd.getOrderId());
		auditQueryWrapper.eq(AuditDO::getSubjectType, AuditSubjectTypeEnum.PURCHASE_ORDER);
		auditQueryWrapper.eq(AuditDO::getState, AuditStateEnum.WAITING_AUDIT);
		auditQueryWrapper.eq(AuditDO::getType, AuditTypeEnum.REVIEWER_AUDIT);
		AuditDO auditDO = auditMapper.selectOne(auditQueryWrapper);

		if (Objects.isNull(auditDO)) {
			// 如果审核记录不存在，抛出异常
			throw new BizException(BizErrorCode.B_BIZ_AUDIT_NOT_FOUND);
		}

		if (orderApproveCmd.getDraft()) {
			return auditConvert.toAudit(auditDO);
		}

		auditDO.setState(AuditStateEnum.AUDIT_SUCCESS);
		auditDO.setAuditAt(LocalDateTime.now());
		auditDO.setAuditBy(orderApproveCmd.getCreatedBy());
		auditDO.setAuditByName(orderApproveCmd.getCreatedByName());
		auditMapper.updateById(auditDO);

		// 自动生成报老板待审核记录（每次都创建新记录）
		AuditDO auditDO1 = new AuditDO();
		auditDO1.setSubjectId(orderApproveCmd.getOrderId());
		auditDO1.setSubjectType(AuditSubjectTypeEnum.PURCHASE_ORDER);
		auditDO1.setType(AuditTypeEnum.BOSS_AUDIT);
		auditDO1.setState(AuditStateEnum.WAITING_AUDIT);
		auditDO1.setCreatedBy(orderApproveCmd.getCreatedBy());
		auditDO1.setCreatedByName(orderApproveCmd.getCreatedByName());
		auditMapper.insert(auditDO1);
		return auditConvert.toAudit(auditDO1);

	}
}

