package com.ecep.contract.ds.contract.tasker;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.StringUtils;

import com.ecep.contract.ContractPayWay;
import com.ecep.contract.Message;
import com.ecep.contract.MessageHolder;
import com.ecep.contract.ds.contract.service.ContractService;
import com.ecep.contract.model.Contract;

import jakarta.persistence.criteria.Path;

/**
 * 对所有合同进行修复
 */
public class ContractRepairAllTasker extends AbstContractRepairTasker {
    private static final Logger logger = LoggerFactory.getLogger(ContractRepairAllTasker.class);

    static class MessageHolderImpl implements MessageHolder {
        List<Message> messages = new ArrayList<>();

        @Override
        public void addMessage(Level level, String message) {
            Message msg = new Message(level, message);
            messages.add(msg);
        }
    }

    @Override
    protected void repair(MessageHolder holder) {
        updateTitle("同步修复所有合同");

        Pageable pageRequest = PageRequest.ofSize(200);
        AtomicInteger counter = new AtomicInteger(0);
        Specification<Contract> spec = (root, query, builder) -> {
            Path<String> parentCode = root.get("parentCode");
            Path<ContractPayWay> payWay = root.get("payWay");
            return builder.or(
                    builder.equal(payWay, ContractPayWay.RECEIVE),
                    builder.and(
                            builder.equal(payWay, ContractPayWay.PAY),
                            builder.or(
                                    builder.equal(parentCode, ""),
                                    builder.isNull(parentCode))));
        };

        updateTitle("遍历所有合同，对每个可以合同的文件进行“修复”操作");
        ContractService contractService = contractCtx.getContractService();
        long total = contractService.count(spec);
        while (true) {
            if (isCancelled()) {
                break;
            }

            Page<Contract> page = contractService.findAll(spec, pageRequest);
            if (page.isEmpty()) {
                break;
            }

            for (Contract contract : page) {
                if (isCancelled()) {
                    break;
                }
                MessageHolder subHolder = holder.sub(
                        counter.get() + " / " + total + "> " + contract.getCode() + " #" + contract.getId() + "> ");
                MessageHolderImpl messageHolder = new MessageHolderImpl();
                try {
                    Contract parent = null;
                    if (contract.getPayWay() == ContractPayWay.PAY) {
                        if (StringUtils.hasText(contract.getParentCode())) {
                            parent = contractCtx.findContractByCode(contract.getParentCode());
                        }
                    }
                    AtomicReference<Contract> contractProperty = new AtomicReference<>(contract);
                    boolean repaired = repair(contractProperty, parent, messageHolder, progress -> {
                    });
                    String msg = messageHolder.messages.stream()
                            .filter(v -> v.getLevel().intValue() > Level.INFO.intValue())
                            .map(Message::getMessage)
                            .collect(Collectors.joining(", "));
                    if (StringUtils.hasText(msg)) {
                        if (repaired) {
                            subHolder.info(msg);
                        } else {
                            subHolder.error(msg);
                        }
                    }
                } catch (Exception e) {
                    subHolder.error("修复失败 #" + contract.getCode() + ": " + e.getMessage());
                    if (logger.isErrorEnabled()) {
                        logger.error(contract.getCode(), e);
                    }
                }
                updateProgress(counter.incrementAndGet(), total);
            }
            if (!page.hasNext()) {
                break;
            }
            pageRequest = page.nextPageable();
        }
    }
}
