package com.erp.warehouse.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.erp.common.core.model.ApiResponse;
import com.erp.warehouse.dto.StockDTO;
import com.erp.warehouse.dto.StockLogDTO;
import com.erp.warehouse.dto.StockOpDTO.*;
import com.erp.warehouse.entity.Stock;
import com.erp.warehouse.service.StockService;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

/**
 * 本地库存管理控制器
 * 提供ERP本地库存的CRUD和操作接口
 */
@Slf4j
@RestController
@RequestMapping("/api/stock")
@RequiredArgsConstructor
public class StockController {

    private final StockService stockService;

    // ==================== 库存查询 ====================

    /**
     * 库存列表（分页）
     * GET /api/stock/list
     */
    @GetMapping("/list")
    public ApiResponse<IPage<StockDTO>> listStocks(
            @RequestParam(required = false) String skuCode,
            @RequestParam(required = false) String skuName,
            @RequestParam(required = false) Long warehouseId,
            @RequestParam(required = false) Boolean lowStock,
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "15") int limit) {

        IPage<StockDTO> result = stockService.listStocks(skuCode, skuName, warehouseId, lowStock, page, limit);
        return ApiResponse.success(result);
    }

    /**
     * 库存详情（按仓库+SKU查询）
     * GET /api/stock/detail
     */
    @GetMapping("/detail")
    public ApiResponse<StockDTO> getStock(
            @RequestParam String skuCode,
            @RequestParam Long warehouseId) {
        try {
            StockDTO stock = stockService.getStock(skuCode, warehouseId);
            return ApiResponse.success(stock);
        } catch (IllegalArgumentException e) {
            return ApiResponse.error(404, e.getMessage());
        }
    }

    /**
     * 库存流水列表
     * GET /api/stock/logs
     */
    @GetMapping("/logs")
    public ApiResponse<IPage<StockLogDTO>> listLogs(
            @RequestParam(required = false) String skuCode,
            @RequestParam(required = false) Long warehouseId,
            @RequestParam(required = false) String changeType,
            @RequestParam(required = false) Long orderId,
            @RequestParam(required = false) String startDate,
            @RequestParam(required = false) String endDate,
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "15") int limit) {

        IPage<StockLogDTO> result = stockService.listLogs(skuCode, warehouseId, changeType, orderId, startDate, endDate, page, limit);
        return ApiResponse.success(result);
    }

    // ==================== 库存操作 ====================

    /**
     * 手动入库
     * POST /api/stock/inbound
     */
    @PostMapping("/inbound")
    public ApiResponse<StockDTO> inbound(@Valid @RequestBody InboundRequest request) {
        try {
            Stock stock = stockService.inbound(
                    request.getSkuCode(),
                    request.getWarehouseId(),
                    request.getQuantity(),
                    request.getRelatedNo(),
                    request.getRemark(),
                    null
            );
            return ApiResponse.success("入库成功", toDTO(stock));
        } catch (Exception e) {
            return ApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 手动出库
     * POST /api/stock/outbound
     */
    @PostMapping("/outbound")
    public ApiResponse<StockDTO> outbound(@Valid @RequestBody OutboundRequest request) {
        try {
            Stock stock = stockService.outbound(
                    request.getSkuCode(),
                    request.getWarehouseId(),
                    request.getQuantity(),
                    request.getRelatedNo(),
                    request.getRemark(),
                    null
            );
            return ApiResponse.success("出库成功", toDTO(stock));
        } catch (Exception e) {
            return ApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 残次品入库
     * POST /api/stock/defective
     */
    @PostMapping("/defective")
    public ApiResponse<Void> defectiveInbound(@Valid @RequestBody InboundRequest request) {
        try {
            stockService.defectiveInbound(
                    request.getSkuCode(),
                    request.getWarehouseId(),
                    request.getQuantity(),
                    request.getRelatedNo(),
                    request.getRemark(),
                    null
            );
            return ApiResponse.success("残次品入库成功", null);
        } catch (Exception e) {
            return ApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 盘点调整库存
     * POST /api/stock/adjust
     */
    @PostMapping("/adjust")
    public ApiResponse<Map<String, Object>> adjust(@Valid @RequestBody AdjustRequest request) {
        try {
            Stock stock = stockService.adjust(
                    request.getSkuCode(),
                    request.getWarehouseId(),
                    request.getQuantity(),
                    request.getDefectiveQuantity(),
                    request.getRemark(),
                    null
            );
            return ApiResponse.success(Map.of(
                    "quantity", stock.getQuantity(),
                    "lockedQuantity", stock.getLockedQuantity(),
                    "defectiveQuantity", stock.getDefectiveQuantity()
            ), "调整成功");
        } catch (Exception e) {
            return ApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 更新预警阈值
     * PUT /api/stock/threshold
     */
    @PutMapping("/threshold")
    public ApiResponse<StockDTO> updateThreshold(@Valid @RequestBody ThresholdRequest request) {
        try {
            Stock stock = stockService.updateThreshold(
                    request.getSkuCode(),
                    request.getWarehouseId(),
                    request.getWarningThreshold()
            );
            return ApiResponse.success("阈值更新成功", toDTO(stock));
        } catch (Exception e) {
            return ApiResponse.error(500, e.getMessage());
        }
    }

    // ==================== 订单联动 ====================

    /**
     * 锁定库存（审核订单时）
     * POST /api/stock/lock
     */
    @PostMapping("/lock")
    public ApiResponse<StockDTO> lock(@Valid @RequestBody LockRequest request) {
        try {
            Stock stock = stockService.lock(request.getSkuCode(), request.getWarehouseId(),
                    request.getQuantity(), request.getOrderId());
            return ApiResponse.success("锁定成功", toDTO(stock));
        } catch (Exception e) {
            return ApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 解锁库存（驳回订单时）
     * POST /api/stock/unlock
     */
    @PostMapping("/unlock")
    public ApiResponse<StockDTO> unlock(@Valid @RequestBody UnlockRequest request) {
        try {
            Stock stock = stockService.unlock(request.getSkuCode(), request.getWarehouseId(),
                    request.getQuantity(), request.getOrderId());
            return ApiResponse.success("解锁成功", toDTO(stock));
        } catch (Exception e) {
            return ApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 预扣库存（两阶段第一阶段）
     * POST /api/stock/reserve
     */
    @PostMapping("/reserve")
    public ApiResponse<Map<String, Object>> reserve(@Valid @RequestBody ReserveRequest request) {
        try {
            StockService.ReserveResult result = stockService.reserve(
                    request.getSkuCode(), request.getWarehouseId(),
                    request.getQuantity(), request.getOrderId(), request.getReserveToken()
            );
            return ApiResponse.success(Map.of(
                    "stock", toDTO(result.stock()),
                    "reserveToken", result.reserveToken()
            ), "预扣成功");
        } catch (Exception e) {
            return ApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 确认预扣出库（两阶段第二阶段）
     * POST /api/stock/confirm-reserve
     */
    @PostMapping("/confirm-reserve")
    public ApiResponse<StockDTO> confirmReserve(@Valid @RequestBody ConfirmReserveRequest request) {
        try {
            Stock stock = stockService.confirmReserve(request.getReserveToken(),
                    request.getOrderId(), request.getTrackingNo());
            return ApiResponse.success("确认出库成功", toDTO(stock));
        } catch (Exception e) {
            return ApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 取消预扣
     * POST /api/stock/cancel-reserve
     */
    @PostMapping("/cancel-reserve")
    public ApiResponse<StockDTO> cancelReserve(@RequestParam String reserveToken, @RequestParam Long orderId) {
        try {
            Stock stock = stockService.cancelReserve(reserveToken, orderId);
            return ApiResponse.success("取消预扣成功", toDTO(stock));
        } catch (Exception e) {
            return ApiResponse.error(500, e.getMessage());
        }
    }

    /**
     * 发货出库
     * POST /api/stock/ship
     */
    @PostMapping("/ship")
    public ApiResponse<StockDTO> ship(@Valid @RequestBody ShipRequest request) {
        try {
            Stock stock = stockService.ship(request.getSkuCode(), request.getWarehouseId(),
                    request.getQuantity(), request.getOrderId(), request.getTrackingNo());
            return ApiResponse.success("发货成功", toDTO(stock));
        } catch (Exception e) {
            return ApiResponse.error(500, e.getMessage());
        }
    }

    private StockDTO toDTO(Stock stock) {
        return StockDTO.builder()
                .id(stock.getId())
                .skuCode(stock.getSkuCode())
                .skuName(stock.getSkuName())
                .warehouseId(stock.getWarehouseId())
                .quantity(stock.getQuantity())
                .lockedQuantity(stock.getLockedQuantity())
                .reservedQuantity(stock.getReservedQuantity())
                .availableQuantity(stock.getAvailableQuantity())
                .defectiveQuantity(stock.getDefectiveQuantity())
                .warningThreshold(stock.getWarningThreshold())
                .isLow(stock.isLowStock())
                .build();
    }
}
