package com.erp.warehouse.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.erp.warehouse.entity.InboundOrder;
import com.erp.warehouse.dto.InboundOrderDTO;
import com.erp.warehouse.entity.Warehouse;
import com.erp.warehouse.mapper.InboundOrderMapper;
import com.erp.warehouse.mapper.WarehouseMapper;
import com.erp.warehouse.service.InboundService;
import com.erp.warehouse.service.StockService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 入库管理服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class InboundServiceImpl implements InboundService {

    private final InboundOrderMapper inboundOrderMapper;
    private final WarehouseMapper warehouseMapper;
    private final StockService stockService;

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

    @Override
    @Transactional
    public InboundOrder createInboundOrder(InboundOrderDTO.CreateRequest request, Long operatorId) {
        Warehouse warehouse = warehouseMapper.selectById(request.getWarehouseId());
        if (warehouse == null) {
            throw new IllegalArgumentException("仓库不存在: " + request.getWarehouseId());
        }

        String inboundNo = generateInboundNo(request.getInboundType());

        InboundOrder order = InboundOrder.builder()
                .inboundNo(inboundNo)
                .inboundType(request.getInboundType())
                .warehouseId(request.getWarehouseId())
                .relatedNo(request.getRelatedNo())
                .supplierId(request.getSupplierId())
                .supplierName(request.getSupplierName())
                .status("pending")
                .remark(request.getRemark())
                .operatorId(operatorId)
                .expectedTime(request.getExpectedTime())
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build();

        inboundOrderMapper.insert(order);
        log.info("创建入库单: inboundNo={}, type={}, warehouseId={}", inboundNo, request.getInboundType(), request.getWarehouseId());
        return order;
    }

    @Override
    @Transactional
    public InboundOrder confirmInbound(Long inboundOrderId, InboundOrderDTO.ConfirmRequest request) {
        InboundOrder order = inboundOrderMapper.selectById(inboundOrderId);
        if (order == null) {
            throw new IllegalArgumentException("入库单不存在: " + inboundOrderId);
        }
        if (!"pending".equals(order.getStatus()) && !"partial".equals(order.getStatus())) {
            throw new IllegalStateException("入库单状态不允许确认: " + order.getStatus());
        }

        boolean allCompleted = true;
        for (InboundOrderDTO.ConfirmItem item : request.getItems()) {
            // 入库增加库存
            if (item.getAcceptedQuantity() != null && item.getAcceptedQuantity() > 0) {
                stockService.inbound(
                        item.getSkuCode(),
                        order.getWarehouseId(),
                        item.getAcceptedQuantity(),
                        order.getInboundNo(),
                        request.getRemark(),
                        order.getOperatorId()
                );
            }
            // 残次品入库
            if (item.getDefectiveQuantity() != null && item.getDefectiveQuantity() > 0) {
                stockService.defectiveInbound(
                        item.getSkuCode(),
                        order.getWarehouseId(),
                        item.getDefectiveQuantity(),
                        order.getInboundNo(),
                        request.getRemark(),
                        null
                );
            }
        }

        // 判断是否全部完成
        if (allCompleted) {
            order.setStatus("completed");
            order.setInboundTime(LocalDateTime.now());
        } else {
            order.setStatus("partial");
        }
        order.setUpdateTime(LocalDateTime.now());
        inboundOrderMapper.updateById(order);

        log.info("确认入库: inboundNo={}, status={}", order.getInboundNo(), order.getStatus());
        return order;
    }

    @Override
    @Transactional
    public void cancelInbound(Long inboundOrderId) {
        InboundOrder order = inboundOrderMapper.selectById(inboundOrderId);
        if (order == null) {
            throw new IllegalArgumentException("入库单不存在: " + inboundOrderId);
        }
        if ("completed".equals(order.getStatus()) || "cancelled".equals(order.getStatus())) {
            throw new IllegalStateException("入库单状态不允许取消: " + order.getStatus());
        }

        order.setStatus("cancelled");
        order.setUpdateTime(LocalDateTime.now());
        inboundOrderMapper.updateById(order);

        log.info("取消入库单: inboundNo={}", order.getInboundNo());
    }

    @Override
    public IPage<InboundOrder> listInboundOrders(String inboundType, Long warehouseId, String status, int page, int limit) {
        Page<InboundOrder> pageParam = new Page<>(page, limit);
        return inboundOrderMapper.selectPageList(pageParam, inboundType, warehouseId, status);
    }

    @Override
    public InboundOrder getInboundOrder(Long id) {
        return inboundOrderMapper.selectById(id);
    }

    @Override
    public InboundOrder getInboundOrderByNo(String inboundNo) {
        return inboundOrderMapper.findByInboundNo(inboundNo);
    }

    private String generateInboundNo(String inboundType) {
        String prefix = switch (inboundType) {
            case "purchase" -> "CGRK";
            case "return" -> "THRK";
            case "transfer" -> "DBRK";
            default -> "RK";
        };
        return prefix + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))
                + String.format("%05d", ORDER_COUNTER.incrementAndGet() % 100000);
    }
}
