package com.eshore.gringotts.web.domain.confirmation.service;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.eshore.gringotts.web.domain.base.service.CheckingService;
import com.eshore.gringotts.web.domain.base.service.SimpleServiceSupport;
import com.eshore.gringotts.web.domain.check.entity.CheckOrder;
import com.eshore.gringotts.web.domain.check.service.CheckOrderService;
import com.eshore.gringotts.web.domain.confirmation.entity.Confirmation;
import com.eshore.gringotts.web.domain.confirmation.repository.ConfirmationRepository;
import com.eshore.gringotts.web.domain.user.entity.User;
import com.eshore.gringotts.web.domain.user.service.UserService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import javax.transaction.Transactional;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.collections.api.factory.Maps;
import org.eclipse.collections.api.map.ImmutableMap;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.stereotype.Service;

/**
 * @author lanyuanxiaoyao
 * @date 2024-11-26
 */
@Slf4j
@Service("com.eshore.gringotts.web.domain.confirmation.service.ConfirmationService")
public class ConfirmationService extends SimpleServiceSupport<Confirmation> implements CheckingService {
    private final ConfirmationRepository confirmationRepository;
    private final UserService userService;
    private final CheckOrderService checkOrderService;
    private final ObjectMapper mapper;

    public ConfirmationService(ConfirmationRepository confirmationRepository, UserService userService, CheckOrderService checkOrderService, Jackson2ObjectMapperBuilder builder) {
        super(confirmationRepository, userService);
        this.confirmationRepository = confirmationRepository;
        this.userService = userService;
        this.checkOrderService = checkOrderService;
        this.mapper = builder.build();
    }

    @Override
    public Long save(Confirmation entity) {
        if (ObjectUtil.isNull(entity.getId()) && confirmationRepository.existsByTarget_Id(entity.getTarget().getId())) {
            throw new ConfirmationDuplicatedException();
        }
        return super.save(entity);
    }

    @Transactional(rollbackOn = Throwable.class)
    public void submit(Long id) throws JsonProcessingException {
        Confirmation confirmation = detailOrThrow(id);
        log.info("confirmation: {}", confirmation);
        confirmation.setState(Confirmation.State.CHECKING);
        checkOrderService.save(new CheckOrder(
                "confirmation_check",
                StrUtil.format("数据资源「{}」的确权申请", confirmation.getTarget().getName()),
                CheckOrder.Type.CONFIRMATION,
                mapper.writeValueAsString(Maps.immutable.of("confirmationId", confirmation.getId())),
                "com.eshore.gringotts.web.domain.confirmation.service.ConfirmationService",
                User.Role.ADMINISTRATOR
        ));
        save(confirmation);
    }

    public void retract(Long id) {
        confirmationRepository.updateStateById(id, Confirmation.State.DRAFT, userService.currentLoginUser());
    }

    @Override
    public void onChecked(CheckOrder order, CheckOrder.Operation operation, ImmutableMap<String, Object> parameters) {
        if (StrUtil.equals(order.getKey(), "confirmation_check")) {
            Long id = (Long) parameters.get("confirmationId");
            switch (operation) {
                case APPLY:
                    confirmationRepository.updateStateById(id, Confirmation.State.NORMAL, userService.currentLoginUser());
                    checkOrderService.over(order.getId());
                    break;
                case REJECT:
                    confirmationRepository.updateStateById(id, Confirmation.State.DRAFT, userService.currentLoginUser());
                    checkOrderService.over(order.getId());
                    break;
            }
        }
    }

    public static final class ConfirmationDuplicatedException extends RuntimeException {
        public ConfirmationDuplicatedException() {
            super("数据资源已绑定确权申请，无法再次申请");
        }
    }
}
