package cn.iocoder.foodnexus.module.erp.service.purchase;

import cn.iocoder.foodnexus.framework.common.enums.CommonStatusEnum;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;
import cn.iocoder.foodnexus.framework.web.core.util.WebFrameworkUtils;
import cn.iocoder.foodnexus.module.erp.api.service.ErpSupplierApi;
import cn.iocoder.foodnexus.module.erp.api.vo.supplier.SupplierAddReqVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.supplier.ErpProductSupplierBindReqVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierAuditReqVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierPageReqVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.supplier.ErpSupplierSaveReqVO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.product.ProductSupplierDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.purchase.ErpSupplierDO;
import cn.iocoder.foodnexus.module.erp.dal.mysql.product.ProductSupplierMapper;
import cn.iocoder.foodnexus.module.erp.dal.mysql.purchase.ErpSupplierMapper;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpAuditStatus;
import cn.iocoder.foodnexus.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.foodnexus.module.product.service.spu.ProductSpuService;
import cn.iocoder.foodnexus.module.system.controller.admin.vo.AuditCommonReqVO;
import cn.iocoder.foodnexus.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.foodnexus.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.foodnexus.framework.common.enums.UserSystemEnum;
import cn.iocoder.foodnexus.module.system.service.dept.DeptService;
import cn.iocoder.foodnexus.module.system.service.user.AdminUserService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Maps;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import static cn.iocoder.foodnexus.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.foodnexus.module.erp.enums.ErrorCodeConstants.*;

/**
 * ERP 供应商 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
public class ErpSupplierServiceImpl implements ErpSupplierService, ErpSupplierApi {

    @Resource
    private ErpSupplierMapper supplierMapper;

    @Autowired
    private ProductSupplierMapper productSupplierMapper;

    @Autowired
    private ProductSpuService productSpuService;

    @Autowired
    @Lazy
    private AdminUserService userService;

    @Autowired
    @Lazy
    private DeptService deptService;

    @Override
    public Long createSupplier(ErpSupplierSaveReqVO createReqVO) {
        ErpSupplierDO supplier = BeanUtils.toBean(createReqVO, ErpSupplierDO.class);
        supplier.setAuditStatus(String.valueOf(ErpAuditStatus.PROCESS.getStatus()));
        supplierMapper.insert(supplier);
        return supplier.getId();
    }

    @Override
    public void updateSupplier(ErpSupplierSaveReqVO updateReqVO) {
        // 校验存在
        validateSupplierExists(updateReqVO.getId());
        // 更新
        ErpSupplierDO updateObj = BeanUtils.toBean(updateReqVO, ErpSupplierDO.class);
        supplierMapper.updateById(updateObj);
    }

    @Override
    public void deleteSupplier(Long id) {
        // 校验存在
        validateSupplierExists(id);
        // 删除
        supplierMapper.deleteById(id);
    }

    private void validateSupplierExists(Long id) {
        if (supplierMapper.selectById(id) == null) {
            throw exception(SUPPLIER_NOT_EXISTS);
        }
    }

    @Override
    public ErpSupplierDO getSupplier(Long id) {
        return supplierMapper.selectById(id);
    }

    @Override
    public ErpSupplierDO validateSupplier(Long id) {
        ErpSupplierDO supplier = supplierMapper.selectById(id);
        if (supplier == null) {
            throw exception(SUPPLIER_NOT_EXISTS);
        }
        if (CommonStatusEnum.isDisable(supplier.getStatus())) {
            throw exception(SUPPLIER_NOT_ENABLE, supplier.getName());
        }
        return supplier;
    }

    @Override
    public List<ErpSupplierDO> getSupplierList(Collection<Long> ids) {
        return supplierMapper.selectByIds(ids);
    }

    @Override
    public PageResult<ErpSupplierDO> getSupplierPage(ErpSupplierPageReqVO pageReqVO) {
        return supplierMapper.selectPage(pageReqVO);
    }

    @Override
    public List<ErpSupplierDO> getSupplierListByStatus(Integer status) {
        return supplierMapper.selectListByStatus(status);
    }

    @Override
    public void audit(ErpSupplierAuditReqVO auditReqVO) {
        Long id = auditReqVO.getId();
        int status = Integer.parseInt(auditReqVO.getAuditStatus());
        ErpSupplierDO supplier = supplierMapper.selectById(id);
        if (supplier == null) {
            throw exception(SUPPLIER_NOT_EXISTS);
        }
        if (ErpAuditStatus.APPROVE.getStatus().toString().equals(supplier.getAuditStatus())) {
            throw exception(SUPPLIER_APPROVE_FAIL);
        }
        if (status == ErpAuditStatus.PROCESS.getStatus()) {
            throw exception("审核失败，提交状态不能为未审核");
        }

        // 2. 更新状态
        supplierMapper.update(Wrappers.<ErpSupplierDO>lambdaUpdate()
                .set(ErpSupplierDO::getAuditor, WebFrameworkUtils.getLoginUserId())
                .set(ErpSupplierDO::getAuditReason, CommonUtil.getEls(auditReqVO.getAuditReason(), ""))
                .set(ErpSupplierDO::getAuditTime, LocalDateTime.now())
                .set(ErpSupplierDO::getAuditStatus, auditReqVO.getAuditStatus())
                .set(ErpSupplierDO::getAuditScore, auditReqVO.getAuditScore())
                .eq(ErpSupplierDO::getId, id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void bindProduct(ErpProductSupplierBindReqVO bindReqVO) {
        validateSupplier(bindReqVO.getSupplierId());

        productSupplierMapper.delete(ProductSupplierDO::getSupplierId, bindReqVO.getSupplierId());
        productSupplierMapper.insertBatch(CommonUtil.listConvert(bindReqVO.getProductIdList(), item -> {
            ProductSupplierDO productSupplierDO = new ProductSupplierDO();
            productSupplierDO.setSupplierId(bindReqVO.getSupplierId());
            productSupplierDO.setProductId(item);
            return productSupplierDO;
        }));
    }

    @Override
    public List<ProductSpuDO> queryBindProduct(Long id) {
        List<ProductSupplierDO> productSupplierDOS = productSupplierMapper.selectList(ProductSupplierDO::getSupplierId, id);

        return productSpuService.getSpuList(CommonUtil.listConvertSet(productSupplierDOS, ProductSupplierDO::getProductId));
    }

    @Override
    public void enable(Long id, Integer status) {
        supplierMapper.update(Wrappers.<ErpSupplierDO>lambdaUpdate()
                .set(ErpSupplierDO::getStatus, status)
                .eq(ErpSupplierDO::getId, id));
    }



    /* --------------- api --------------- */


    @Override
    public Long createByDept(Long deptId, SupplierAddReqVO supplier) {
        return this.createSupplier(BeanUtils.toBean(supplier, ErpSupplierSaveReqVO.class, item ->
                item.setSystemDeptId(deptId)));
    }

    @Override
    public void updateByDept(Long deptId, SupplierAddReqVO supplier) {
        ErpSupplierDO customer = supplierMapper.selectOne(ErpSupplierDO::getSystemDeptId, deptId);
        if (CommonUtil.isEmpty(customer)) {
            this.createSupplier(BeanUtils.toBean(supplier, ErpSupplierSaveReqVO.class, item ->
                    item.setSystemDeptId(deptId)));
        } else {
            this.updateSupplier(BeanUtils.toBean(supplier, ErpSupplierSaveReqVO.class, item ->{
                item.setSystemDeptId(deptId);
                item.setId(customer.getId());
            }));
        }
    }

    @Override
    public void deleteByDept(Long deptId) {
        supplierMapper.delete(ErpSupplierDO::getSystemDeptId, deptId);
    }

    @Override
    public Long querySupplierIdByUserId(Long userId) {
        AdminUserDO user = userService.getUser(userId);
        if (!UserSystemEnum.SUPPLIER.getKey().equals(user.getUserSystem())) {
            throw exception(ERROR_SUPPLIER_USER);
        }
        DeptDO topDept = deptService.getTopDept(user.getDeptId());
        ErpSupplierDO supplier = supplierMapper.selectOne(ErpSupplierDO::getSystemDeptId, topDept.getId());
        if (CommonUtil.isEmpty(supplier)) {
            throw exception(SUPPLIER_NOT_EXISTS);
        }
        if (CommonStatusEnum.isDisable(supplier.getStatus())) {
            throw exception(SUPPLIER_NOT_ENABLE, supplier.getName());
        }
        return supplier.getId();
    }

    @Override
    public Map<Long, String> queryNameMapByIds(Collection<Long> list) {
        if (CommonUtil.isEmpty(list)) {
            return Maps.newHashMap();
        }
        return CommonUtil.listConvertMap(supplierMapper.selectByIds(list), ErpSupplierDO::getId, ErpSupplierDO::getName);
    }

    @Override
    public String queryNameById(Long supplierId) {
        return Optional.ofNullable(supplierMapper.selectById(supplierId)).map(ErpSupplierDO::getName).orElse("");
    }

    @Override
    public BigDecimal querySettlementFloatingRate(Long supplierId) {
        return Optional.ofNullable(supplierMapper.selectById(supplierId)).map(ErpSupplierDO::getSettlementFloatingRate).orElse(BigDecimal.ZERO);
    }
}
