/*
 * Copyright ©2023 CJB-CNIT Team. All rights reserved
 */
package com.openhis.web.reportmanage.appservice.impl;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

import com.openhis.administration.domain.Location;
import com.openhis.administration.domain.Supplier;
import com.openhis.administration.service.ILocationService;
import com.openhis.web.reportmanage.dto.InboundReportInitDto;
import com.openhis.web.reportmanage.dto.MonthlySettlementInitDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.core.common.core.domain.R;
import com.openhis.common.constant.CommonConstants;
import com.openhis.common.enums.DispenseStatus;
import com.openhis.common.enums.RequestStatus;
import com.openhis.common.enums.SupplyStatus;
import com.openhis.common.enums.SupplyType;
import com.openhis.web.reportmanage.appservice.IMonthlySettlementReportAppService;
import com.openhis.web.reportmanage.dto.AmountNumberDto;
import com.openhis.web.reportmanage.dto.MonthlySettlementDto;
import com.openhis.web.reportmanage.mapper.MonthlySettlementReportMapper;

/**
 * 月末结算报表 impl
 *
 * @author liuhr
 * @date 2025-07-15
 */
@Service
public class MonthlySettlementReportAppServiceImpl implements IMonthlySettlementReportAppService {

    @Autowired
    private MonthlySettlementReportMapper monthlySettlementReportMapper;
    @Autowired
    private ILocationService locationService;


    /**
     * 页面初始化
     *
     * @return 初始化信息
     */
    @Override
    public R<?> init() {
        MonthlySettlementInitDto initDto = new MonthlySettlementInitDto();

        // 查询库房列表
        List<Location> locationList = locationService.getPharmacyCabinetList();

        // 库房信息
        List<MonthlySettlementInitDto.locationListOption> LocationListOptions = locationList.stream()
            .map(supplier -> new MonthlySettlementInitDto.locationListOption(supplier.getId(), supplier.getName()))
            .collect(Collectors.toList());

        initDto.setLocationListOptions(LocationListOptions);

        return R.ok(initDto);
    }

    /**
     * 月末结算报表（统计筛选时间区内）
     *
     * @param locationId 库房
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 月末结算报表
     */
    @Override
    public R<?> selectMonthlySettlementReport(Long locationId, String startTime, String endTime) {
        MonthlySettlementDto monthlySettlementDto = new MonthlySettlementDto();
        monthlySettlementDto.setLocationId(locationId);

        // 期初金额
        monthlySettlementDto.setInitialAmount(monthlySettlementReportMapper.selectAmount(locationId, startTime));
        // 期末金额
        monthlySettlementDto.setFinalAmount(monthlySettlementReportMapper.selectAmount(locationId, endTime));
        // 采购入库,typeEnum=1 采购入库
        AmountNumberDto purchaseInObj =
            monthlySettlementReportMapper.selectAmountNumber(locationId, SupplyType.PURCHASE_INVENTORY.getValue(),
                SupplyStatus.AGREE.getValue(), DispenseStatus.COMPLETED.getValue(), startTime, endTime);
        // 采购退货,typeEnum=5 采购退货
        AmountNumberDto purchaseReturnObj =
            monthlySettlementReportMapper.selectAmountNumber(locationId, SupplyType.PRODUCT_RETURN.getValue(),
                SupplyStatus.AGREE.getValue(), DispenseStatus.COMPLETED.getValue(), startTime, endTime);
        // 领用出库,typeEnum=7 领用出库
        AmountNumberDto applyOutObj =
            monthlySettlementReportMapper.selectAmountNumber(locationId, SupplyType.ISSUE_INVENTORY.getValue(),
                SupplyStatus.AGREE.getValue(), DispenseStatus.COMPLETED.getValue(), startTime, endTime);
        // 领用退货,typeEnum=9 领用退货
        AmountNumberDto applyReturnObj =
            monthlySettlementReportMapper.selectAmountNumber(locationId, SupplyType.RETURN_ISSUE.getValue(),
                SupplyStatus.AGREE.getValue(), DispenseStatus.COMPLETED.getValue(), startTime, endTime);
        // 调拨入库,typeEnum=2,8 商品调拨,商品批量调拨
        AmountNumberDto transferInObj = monthlySettlementReportMapper.selectTransferInAmountNumber(locationId,
            SupplyType.PRODUCT_TRANSFER.getValue(), SupplyType.PRODUCT_BATCH_TRANSFER.getValue(),
            SupplyStatus.AGREE.getValue(), DispenseStatus.COMPLETED.getValue(), startTime, endTime);
        // 调拨出库,typeEnum=2,8 商品调拨,商品批量调拨
        AmountNumberDto transferOutObj = monthlySettlementReportMapper.selectTransferOutAmountNumber(locationId,
            SupplyType.PRODUCT_TRANSFER.getValue(), SupplyType.PRODUCT_BATCH_TRANSFER.getValue(),
            SupplyStatus.AGREE.getValue(), DispenseStatus.COMPLETED.getValue(), startTime, endTime);
        // 盘点出库,typeEnum=4,10 商品盘点,商品批量盘点
        AmountNumberDto profitLossObj = monthlySettlementReportMapper.selectProfitLossAmountNumber(locationId,
            SupplyType.PRODUCT_STOCKTAKING.getValue(), SupplyType.PRODUCT_BATCH_STOCKTAKING.getValue(),
            SupplyStatus.AGREE.getValue(), DispenseStatus.COMPLETED.getValue(), startTime, endTime);
        // 报损单,typeEnum=6 报损单
        AmountNumberDto lossObj =
            monthlySettlementReportMapper.selectLossAmountNumber(locationId, SupplyType.LOSS_REPORT_FORM.getValue(),
                SupplyStatus.AGREE.getValue(), DispenseStatus.COMPLETED.getValue(), startTime, endTime);
        // 药品和耗材发放金额
        monthlySettlementDto.setDrugIssueAmount(monthlySettlementReportMapper.selectDrugIssue(locationId,
            RequestStatus.COMPLETED.getValue(), DispenseStatus.COMPLETED.getValue(), CommonConstants.TableName.MED_MEDICATION_REQUEST,
            CommonConstants.TableName.WOR_DEVICE_REQUEST, startTime, endTime));

        // 预期期末金额 = 期初金额 + 采购入库金额 - 领用出库金额 + 领用退货金额 + 调拨入库金额 - 调拨出库金额 - 报损单金额 - 药品和耗材发放金额
        BigDecimal expectFinalAmount = monthlySettlementDto.getInitialAmount().add(purchaseInObj.getTotalAmount())
            .subtract(applyOutObj.getTotalAmount()).add(applyReturnObj.getTotalAmount())
            .add(transferInObj.getTotalAmount()).subtract(transferOutObj.getTotalAmount())
            .subtract(lossObj.getTotalAmount()).subtract(monthlySettlementDto.getDrugIssueAmount());

        // 偏移量 = 实际期末金额 - 预期期末金额
        BigDecimal offsetAmount = monthlySettlementDto.getFinalAmount().subtract(expectFinalAmount);

        // 实体类赋值
        monthlySettlementDto.setPurchaseInAmount(purchaseInObj.getTotalAmount())
            .setPurchaseInNumber(purchaseInObj.getTotalNumber())
            .setPurchaseReturnAmount(purchaseReturnObj.getTotalAmount())
            .setPurchaseReturnNumber(purchaseReturnObj.getTotalNumber()).setApplyOutAmount(applyOutObj.getTotalAmount())
            .setApplyOutNumber(applyOutObj.getTotalNumber()).setApplyReturnAmount(applyReturnObj.getTotalAmount())
            .setApplyReturnNumber(applyReturnObj.getTotalNumber()).setTransferInAmount(transferInObj.getTotalAmount())
            .setTransferInNumber(transferInObj.getTotalNumber()).setTransferOutAmount(transferOutObj.getTotalAmount())
            .setTransferOutNumber(transferOutObj.getTotalNumber())
            .setCheckProfitLossAmount(profitLossObj.getTotalAmount())
            .setCheckProfitLossNumber(profitLossObj.getTotalNumber()).setLossAmount(lossObj.getTotalAmount())
            .setLossNumber(lossObj.getTotalNumber()).setExpectFinalAmount(expectFinalAmount)
            .setOffsetAmount(offsetAmount);

        return R.ok(monthlySettlementDto);
    }

}