package com.ruoyi.web.modules.trading.support;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.web.modules.trading.domain.BizDistributor;
import com.ruoyi.web.modules.trading.domain.BizSupplier;
import com.ruoyi.web.modules.trading.domain.BizTradeOrder;
import com.ruoyi.web.modules.trading.domain.BizTradeOrderLine;
import com.ruoyi.web.modules.trading.mapper.BizDistributorMapper;
import com.ruoyi.web.modules.trading.mapper.BizMarketEntryEarTagMapper;
import com.ruoyi.web.modules.trading.mapper.BizSupplierMapper;

/**
 * 交易订单保存与完成支付校验（R1～R8、§6.5）。
 */
@Component
public class TradeOrderValidation
{
    @Autowired
    private BizSupplierMapper bizSupplierMapper;

    @Autowired
    private BizDistributorMapper bizDistributorMapper;

    @Autowired
    private TradeOrderEarTagResolver tradeOrderEarTagResolver;

    @Autowired
    private BizMarketEntryEarTagMapper bizMarketEntryEarTagMapper;

    @Autowired
    private TradeOrderGradeResolver tradeOrderGradeResolver;

    public void prepareAndValidateForSave(BizTradeOrder row)
    {
        if (row == null)
        {
            throw new ServiceException("订单数据不能为空");
        }
        trimRemark(row);
        if (row.getSupplierId() == null)
        {
            throw new ServiceException(TradeOrderRules.MSG_SUPPLIER_REQUIRED);
        }
        if (row.getDistributorId() == null)
        {
            throw new ServiceException(TradeOrderRules.MSG_DISTRIBUTOR_REQUIRED);
        }
        assertSupplierActive(row.getSupplierId());
        assertDistributorActive(row.getDistributorId());

        List<BizTradeOrderLine> lines = normalizeLines(row.getLineList());
        if (lines.isEmpty())
        {
            throw new ServiceException(TradeOrderRules.MSG_LINE_EMPTY);
        }
        validateNoDuplicateEarTag(lines);
        validateWeightAndAmount(lines);
        tradeOrderGradeResolver.assignGrades(lines);
        validateEarTagsEligible(row.getSupplierId(), row.getId(), lines);

        row.setLineList(lines);
        row.setTotalHeads(lines.size());
        row.setTotalAmount(sumAmount(lines));
    }

    public void assertPendingForUpdate(BizTradeOrder existing)
    {
        if (existing == null)
        {
            throw new ServiceException(TradeOrderRules.MSG_NOT_FOUND);
        }
        if (TradeOrderRules.ORDER_STATUS_COMPLETED.equals(existing.getOrderStatus()))
        {
            throw new ServiceException(TradeOrderRules.MSG_COMPLETED_NO_EDIT);
        }
    }

    public void assertSupplierActiveForQuery(Long supplierId)
    {
        if (supplierId == null)
        {
            throw new ServiceException(TradeOrderRules.MSG_SUPPLIER_REQUIRED);
        }
        assertSupplierActive(supplierId);
    }

    public void validatePayVoucher(BizTradeOrder payRequest)
    {
        if (payRequest == null || payRequest.getId() == null)
        {
            throw new ServiceException("订单主键不能为空");
        }
        if (StringUtils.isEmpty(payRequest.getPayVoucherUrl())
                || StringUtils.isEmpty(payRequest.getPayVoucherPath()))
        {
            throw new ServiceException(TradeOrderRules.MSG_PAY_VOUCHER_REQUIRED);
        }
        String path = payRequest.getPayVoucherPath().toLowerCase(Locale.ROOT);
        if (!path.endsWith(".jpg") && !path.endsWith(".jpeg") && !path.endsWith(".png"))
        {
            throw new ServiceException(TradeOrderRules.MSG_PAY_VOUCHER_INVALID);
        }
    }

    public BizSupplier assertSupplierFeeConfigured(Long supplierId)
    {
        BizSupplier supplier = bizSupplierMapper.selectBizSupplierById(supplierId);
        if (supplier == null)
        {
            throw new ServiceException(TradeOrderRules.MSG_SUPPLIER_NOT_FOUND);
        }
        if (supplier.getFeeMethod() == null)
        {
            throw new ServiceException(TradeOrderRules.MSG_FEE_NOT_CONFIGURED);
        }
        return supplier;
    }

    public void validateOrderStillValidForPay(BizTradeOrder row)
    {
        prepareAndValidateForSave(row);
    }

    private static List<BizTradeOrderLine> normalizeLines(List<BizTradeOrderLine> raw)
    {
        List<BizTradeOrderLine> lines = new ArrayList<>();
        if (raw == null)
        {
            return lines;
        }
        Set<String> seen = new HashSet<>();
        for (BizTradeOrderLine item : raw)
        {
            if (item == null || StringUtils.isEmpty(item.getEarTag()))
            {
                continue;
            }
            String tag = item.getEarTag().trim();
            EarTagCodec.parse(tag);
            if (!seen.add(tag))
            {
                throw new ServiceException(TradeOrderRules.MSG_EAR_TAG_DUP + "：" + tag);
            }
            BizTradeOrderLine line = new BizTradeOrderLine();
            line.setEarTag(tag);
            line.setWeight(item.getWeight());
            line.setAmount(item.getAmount());
            lines.add(line);
        }
        return lines;
    }

    private static void validateNoDuplicateEarTag(List<BizTradeOrderLine> lines)
    {
        Set<String> seen = new HashSet<>();
        for (BizTradeOrderLine line : lines)
        {
            if (!seen.add(line.getEarTag()))
            {
                throw new ServiceException(TradeOrderRules.MSG_EAR_TAG_DUP + "：" + line.getEarTag());
            }
        }
    }

    private static void validateWeightAndAmount(List<BizTradeOrderLine> lines)
    {
        for (BizTradeOrderLine line : lines)
        {
            if (line.getWeight() == null || line.getWeight().compareTo(BigDecimal.ZERO) <= 0
                    || line.getAmount() == null || line.getAmount().compareTo(BigDecimal.ZERO) <= 0)
            {
                throw new ServiceException(TradeOrderRules.MSG_WEIGHT_AMOUNT_INVALID);
            }
        }
    }

    private void validateEarTagsEligible(Long supplierId, Long excludeOrderId, List<BizTradeOrderLine> lines)
    {
        List<String> marketTags = bizMarketEntryEarTagMapper.selectDistinctEarTagsBySupplierId(supplierId);
        if (marketTags == null || marketTags.isEmpty())
        {
            throw new ServiceException(TradeOrderRules.MSG_NO_MARKET_EAR_TAG);
        }
        List<String> eligible = tradeOrderEarTagResolver.listEligible(supplierId, excludeOrderId);
        Set<String> eligibleSet = new HashSet<>(eligible);
        Set<String> occupied = tradeOrderEarTagResolver.loadOccupiedEarTags(excludeOrderId);
        for (BizTradeOrderLine line : lines)
        {
            String tag = line.getEarTag();
            if (!eligibleSet.contains(tag))
            {
                if (occupied.contains(tag))
                {
                    throw new ServiceException(TradeOrderRules.MSG_EAR_TAG_OCCUPIED + "：" + tag);
                }
                throw new ServiceException(String.format(TradeOrderRules.MSG_EAR_TAG_INVALID, tag));
            }
        }
    }

    private void assertSupplierActive(Long supplierId)
    {
        BizSupplier supplier = bizSupplierMapper.selectBizSupplierById(supplierId);
        if (supplier == null)
        {
            throw new ServiceException(TradeOrderRules.MSG_SUPPLIER_NOT_FOUND);
        }
    }

    private void assertDistributorActive(Long distributorId)
    {
        BizDistributor distributor = bizDistributorMapper.selectBizDistributorById(distributorId);
        if (distributor == null)
        {
            throw new ServiceException(TradeOrderRules.MSG_DISTRIBUTOR_NOT_FOUND);
        }
    }

    private static BigDecimal sumAmount(List<BizTradeOrderLine> lines)
    {
        BigDecimal sum = BigDecimal.ZERO;
        for (BizTradeOrderLine line : lines)
        {
            sum = sum.add(line.getAmount());
        }
        return sum.setScale(2, RoundingMode.HALF_UP);
    }

    private static void trimRemark(BizTradeOrder row)
    {
        if (row.getRemark() == null)
        {
            return;
        }
        String remark = row.getRemark().trim();
        row.setRemark(remark.isEmpty() ? null : remark);
        if (remark.length() > TradeOrderRules.MAX_REMARK_LEN)
        {
            throw new ServiceException("备注长度不能超过 " + TradeOrderRules.MAX_REMARK_LEN + " 字");
        }
    }
}
