package com.erp.purchase.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.erp.purchase.client.FinanceFeignClient;
import com.erp.purchase.client.WarehouseFeignClient;
import com.erp.purchase.dto.PurchaseReturnDTO;
import com.erp.purchase.entity.PurchaseOrder;
import com.erp.purchase.entity.PurchaseReturn;
import com.erp.purchase.enums.PurchaseReturnStatus;
import com.erp.purchase.enums.PurchaseOrderStatus;
import com.erp.purchase.exception.BusinessException;
import com.erp.purchase.mapper.PurchaseOrderMapper;
import com.erp.purchase.mapper.PurchaseReturnMapper;
import com.erp.purchase.mapper.SupplierMapper;
import com.erp.purchase.service.PurchaseReturnService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class PurchaseReturnServiceImpl implements PurchaseReturnService {

    private final PurchaseReturnMapper purchaseReturnMapper;
    private final PurchaseOrderMapper purchaseOrderMapper;
    private final SupplierMapper supplierMapper;
    private final WarehouseFeignClient warehouseClient;
    private final FinanceFeignClient financeClient;

    private static final AtomicLong RETURN_COUNTER = new AtomicLong(System.currentTimeMillis() % 100000);

    @Override
    public IPage<PurchaseReturn> listPage(PurchaseReturnDTO.QueryRequest query) {
        Page<PurchaseReturn> page = new Page<>(query.getPage(), query.getLimit());
        return purchaseReturnMapper.selectPageList(page, query.getReturnNo(), query.getPurchaseOrderId(),
                query.getSupplierId(), query.getStatus(), query.getReturnType());
    }

    @Override
    public PurchaseReturn getById(Long id) {
        PurchaseReturn ret = purchaseReturnMapper.selectById(id);
        if (ret == null) throw new BusinessException("采购退货单不存在");
        return ret;
    }

    @Override
    public PurchaseReturn getByReturnNo(String returnNo) {
        return purchaseReturnMapper.findByReturnNo(returnNo);
    }

    @Override
    @Transactional
    public PurchaseReturn create(PurchaseReturnDTO.CreateRequest request, Long operatorId) {
        PurchaseOrder order = purchaseOrderMapper.selectById(request.getPurchaseOrderId());
        if (order == null) throw new BusinessException("采购订单不存在");

        String returnNo = generateReturnNo();

        List<PurchaseReturn.PurchaseReturnItem> items = new ArrayList<>();
        int totalQty = 0;
        BigDecimal totalAmt = BigDecimal.ZERO;

        for (PurchaseReturnDTO.ReturnItemRequest itemReq : request.getItems()) {
            BigDecimal price = itemReq.getPrice() != null ? itemReq.getPrice() : BigDecimal.ZERO;
            int retQty = itemReq.getReturnQuantity() != null ? itemReq.getReturnQuantity() : 0;
            BigDecimal amount = price.multiply(new BigDecimal(retQty));

            PurchaseReturn.PurchaseReturnItem item = PurchaseReturn.PurchaseReturnItem.builder()
                    .skuCode(itemReq.getSkuCode())
                    .skuName(itemReq.getSkuName())
                    .unit(itemReq.getUnit())
                    .purchaseQuantity(itemReq.getPurchaseQuantity())
                    .returnQuantity(retQty)
                    .price(price)
                    .amount(amount)
                    .remark(itemReq.getRemark())
                    .build();
            items.add(item);
            totalQty += retQty;
            totalAmt = totalAmt.add(amount);
        }

        PurchaseReturn ret = PurchaseReturn.builder()
                .returnNo(returnNo)
                .purchaseOrderId(order.getId())
                .purchaseOrderNo(order.getOrderNo())
                .supplierId(order.getSupplierId())
                .supplierName(order.getSupplierName())
                .warehouseId(request.getWarehouseId() != null ? request.getWarehouseId() : order.getWarehouseId())
                .status(PurchaseReturnStatus.PENDING.getCode())
                .totalQuantity(totalQty)
                .totalAmount(totalAmt)
                .refundedAmount(BigDecimal.ZERO)
                .returnReason(request.getReturnReason())
                .returnType(request.getReturnType())
                .remark(request.getRemark())
                .operatorId(operatorId)
                .createBy(operatorId)
                .createTime(LocalDateTime.now())
                .updateBy(operatorId)
                .updateTime(LocalDateTime.now())
                .deleted(0)
                .items(items)
                .build();

        purchaseReturnMapper.insert(ret);
        log.info("创建采购退货单: returnNo={}, orderNo={}, qty={}", returnNo, order.getOrderNo(), totalQty);
        return ret;
    }

    @Override
    @Transactional
    public PurchaseReturn confirmReturn(Long returnId, PurchaseReturnDTO.ConfirmRequest request, Long operatorId) {
        PurchaseReturn ret = purchaseReturnMapper.selectById(returnId);
        if (ret == null) throw new BusinessException("采购退货单不存在");
        if (!PurchaseReturnStatus.PENDING.getCode().equals(ret.getStatus()) &&
            !PurchaseReturnStatus.PARTIAL.getCode().equals(ret.getStatus())) {
            throw new BusinessException("退货单状态不允许确认");
        }

        PurchaseOrder order = purchaseOrderMapper.selectById(ret.getPurchaseOrderId());
        if (order == null) throw new BusinessException("采购订单不存在");

        // 调用仓库服务创建出库单（退货出库）
        try {
            WarehouseFeignClient.OutboundRequest outboundRequest = WarehouseFeignClient.OutboundRequest.builder()
                    .relatedNo(ret.getReturnNo())
                    .outboundType("purchase_return")
                    .warehouseId(ret.getWarehouseId())
                    .remark(request.getRemark())
                    .items(request.getItems().stream()
                            .map(i -> WarehouseFeignClient.OutboundRequest.OutboundItem.builder()
                                    .skuCode(i.getSkuCode())
                                    .quantity(i.getReturnQuantity())
                                    .build())
                            .collect(Collectors.toList()))
                    .build();

            WarehouseFeignClient.OutboundResponse resp = warehouseClient.createOutbound(outboundRequest, operatorId);
            ret.setWarehouseOutboundNo(resp.getOutboundNo());
        } catch (Exception e) {
            log.warn("调用仓库服务创建出库单失败: returnNo={}, error={}", ret.getReturnNo(), e.getMessage());
        }

        int totalReturnQty = 0;
        BigDecimal returnAmt = BigDecimal.ZERO;

        for (PurchaseReturnDTO.ConfirmRequest.ConfirmItem ci : request.getItems()) {
            totalReturnQty += ci.getReturnQuantity() != null ? ci.getReturnQuantity() : 0;

            BigDecimal price = BigDecimal.ZERO;
            if (ret.getItems() != null) {
                for (PurchaseReturn.PurchaseReturnItem item : ret.getItems()) {
                    if (item.getSkuCode().equals(ci.getSkuCode())) {
                        price = item.getPrice();
                        break;
                    }
                }
            }
            returnAmt = returnAmt.add(price.multiply(new BigDecimal(ci.getReturnQuantity() != null ? ci.getReturnQuantity() : 0)));
        }

        ret.setTotalQuantity(totalReturnQty);
        ret.setOutboundTime(LocalDateTime.now());
        ret.setStatus(PurchaseReturnStatus.COMPLETED.getCode());
        ret.setRefundedAmount(returnAmt);
        ret.setUpdateBy(operatorId);
        ret.setUpdateTime(LocalDateTime.now());
        purchaseReturnMapper.updateById(ret);

        // 更新采购单退货状态
        order.setStatus(PurchaseOrderStatus.PARTIAL_RETURN.getCode());
        order.setUpdateTime(LocalDateTime.now());
        purchaseOrderMapper.updateById(order);

        // 通知财务处理退款（红字发票/应付账款调整）
        try {
            financeClient.processRefund(ret.getPurchaseOrderNo(), ret.getReturnNo(), returnAmt);
        } catch (Exception e) {
            log.warn("通知财务处理退款失败: returnNo={}, error={}", ret.getReturnNo(), e.getMessage());
        }

        log.info("确认采购退货: returnNo={}, qty={}, amt={}", ret.getReturnNo(), totalReturnQty, returnAmt);
        return ret;
    }

    @Override
    @Transactional
    public void cancel(Long returnId, Long operatorId) {
        PurchaseReturn ret = purchaseReturnMapper.selectById(returnId);
        if (ret == null) throw new BusinessException("采购退货单不存在");
        if (!PurchaseReturnStatus.PENDING.getCode().equals(ret.getStatus())) {
            throw new BusinessException("只有待退货状态可以取消");
        }
        ret.setStatus(PurchaseReturnStatus.CANCELLED.getCode());
        ret.setUpdateBy(operatorId);
        ret.setUpdateTime(LocalDateTime.now());
        purchaseReturnMapper.updateById(ret);
        log.info("取消采购退货单: returnNo={}", ret.getReturnNo());
    }

    private String generateReturnNo() {
        String ts = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"));
        return "PR" + ts + String.format("%04d", RETURN_COUNTER.incrementAndGet());
    }
}
