package com.aegis.resource.warehouse.service.impl;

import com.aegis.common.exception.ServiceException;
import com.aegis.common.utils.SecurityUtils;
import com.aegis.common.utils.StringUtils;
import com.aegis.resource.warehouse.domain.Warehouse;
import com.aegis.resource.warehouse.mapper.ResourceWarehouseMapper;
import com.aegis.resource.warehouse.service.IResourceWarehouseService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ResourceWarehouseServiceImpl extends ServiceImpl<ResourceWarehouseMapper, Warehouse>
    implements IResourceWarehouseService {

    private static final String STATUS_NORMAL = "0";
    private static final String DEL_FLAG_NORMAL = "0";
    private static final String DEL_FLAG_DELETED = "2";

    @Override
    public List<Warehouse> listByCondition(Warehouse condition) {
        LambdaQueryWrapper<Warehouse> wrapper = buildConditionWrapper(condition);
        wrapper.orderByDesc(Warehouse::getCreateTime);
        return list(wrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(Warehouse entity) {
        ensureWarehouseCodeUnique(entity.getWarehouseCode(), null);
        // 如果存在已删除的记录使用相同编码，先物理删除它，避免唯一约束冲突
        removeDeletedWarehouseByCode(entity.getWarehouseCode());
        String operator = SecurityUtils.getUsername();
        Date now = new Date();
        entity.setCreateBy(operator);
        entity.setCreateTime(now);
        entity.setUpdateBy(operator);
        entity.setUpdateTime(now);
        if (StringUtils.isEmpty(entity.getStatus())) {
            entity.setStatus(STATUS_NORMAL);
        }
        if (StringUtils.isEmpty(entity.getDelFlag())) {
            entity.setDelFlag(DEL_FLAG_NORMAL);
        }
        return super.save(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(Warehouse entity) {
        if (entity.getId() == null) {
            throw new ServiceException("仓库ID不能为空");
        }
        ensureWarehouseCodeUnique(entity.getWarehouseCode(), entity.getId());
        entity.setUpdateBy(SecurityUtils.getUsername());
        entity.setUpdateTime(new Date());
        return super.updateById(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeById(Serializable id) {
        return softDeleteByIds(Collections.singleton(id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByIds(Collection<?> idList) {
        return softDeleteByIds(idList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatus(Long id, String status) {
        if (id == null || StringUtils.isEmpty(status)) {
            throw new ServiceException("仓库ID和状态不能为空");
        }
        boolean updated = lambdaUpdate()
            .eq(Warehouse::getId, id)
            .set(Warehouse::getStatus, status)
            .set(Warehouse::getUpdateBy, SecurityUtils.getUsername())
            .set(Warehouse::getUpdateTime, new Date())
            .update();
        if (!updated) {
            throw new ServiceException("仓库不存在或状态更新失败");
        }
        return true;
    }

    private boolean softDeleteByIds(Collection<?> idList) {
        if (idList == null || idList.isEmpty()) {
            return true;
        }
        return lambdaUpdate()
            .in(Warehouse::getId, idList)
            .set(Warehouse::getDelFlag, DEL_FLAG_DELETED)
            .set(Warehouse::getUpdateBy, SecurityUtils.getUsername())
            .set(Warehouse::getUpdateTime, new Date())
            .update();
    }

    private void ensureWarehouseCodeUnique(String warehouseCode, Long id) {
        if (StringUtils.isEmpty(warehouseCode)) {
            throw new ServiceException("仓库编码不能为空");
        }
        LambdaQueryWrapper<Warehouse> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Warehouse::getWarehouseCode, warehouseCode);
        wrapper.eq(Warehouse::getDelFlag, DEL_FLAG_NORMAL);
        if (id != null) {
            wrapper.ne(Warehouse::getId, id);
        }
        if (count(wrapper) > 0) {
            throw new ServiceException("仓库编码已存在：" + warehouseCode);
        }
    }

    /**
     * 物理删除已删除状态的仓库记录（用于解决唯一约束冲突）
     * @param warehouseCode 仓库编码
     */
    private void removeDeletedWarehouseByCode(String warehouseCode) {
        if (StringUtils.isEmpty(warehouseCode)) {
            return;
        }
        LambdaQueryWrapper<Warehouse> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Warehouse::getWarehouseCode, warehouseCode);
        wrapper.eq(Warehouse::getDelFlag, DEL_FLAG_DELETED);
        remove(wrapper);
    }

    private LambdaQueryWrapper<Warehouse> buildConditionWrapper(Warehouse condition) {
        LambdaQueryWrapper<Warehouse> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Warehouse::getDelFlag, DEL_FLAG_NORMAL);
        if (condition == null) {
            return wrapper;
        }
        wrapper.like(StringUtils.isNotEmpty(condition.getWarehouseName()), Warehouse::getWarehouseName,
            condition.getWarehouseName());
        wrapper.like(StringUtils.isNotEmpty(condition.getWarehouseCode()), Warehouse::getWarehouseCode,
            condition.getWarehouseCode());
        wrapper.eq(StringUtils.isNotEmpty(condition.getWarehouseType()), Warehouse::getWarehouseType,
            condition.getWarehouseType());
        wrapper.like(StringUtils.isNotEmpty(condition.getBelongOrgName()), Warehouse::getBelongOrgName,
            condition.getBelongOrgName());
        wrapper.eq(StringUtils.isNotEmpty(condition.getBelongOrgType()), Warehouse::getBelongOrgType,
            condition.getBelongOrgType());
        wrapper.eq(StringUtils.isNotEmpty(condition.getStatus()), Warehouse::getStatus, condition.getStatus());
        return wrapper;
    }
}