package com.sptg.estate.biz.service.impl;

import com.baomidou.mybatisplus.enums.SqlLike;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.toolkit.IdWorker;
import com.sptg.common.core.beans.ExcelResultEnum;
import com.sptg.common.core.beans.ResultBean;
import com.sptg.common.core.beans.ResultEnum;
import com.sptg.common.core.constant.OperationConstant;
import com.sptg.common.core.constant.SymbolConstant;
import com.sptg.common.core.util.CommonUtil;
import com.sptg.estate.api.dto.ResidentialDto;
import com.sptg.estate.api.dto.RoomDto;
import com.sptg.estate.api.entity.*;
import com.sptg.estate.api.enums.EstateEnum;
import com.sptg.estate.biz.mapper.RoomMapper;
import com.sptg.estate.biz.service.*;
import com.sptg.permissions.api.entity.DeviceAuthorize;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * title: RoomServiceImpl
 * package: com.sptg.estate.biz.security.impl
 * description: 房间 服务层实现层
 *
 *
 *
 */
@Service
@RequiredArgsConstructor
public class RoomServiceImpl extends ServiceImpl<RoomMapper, Room> implements RoomServiceInterface {

    private final UnitServiceInterface unitServiceInterface;
    private final ResidentialServiceInterface residentialServiceInterface;
    private final RedisTemplate<String,String> redisTemplate;
    private final BuildingServiceInterface buildingServiceInterface;
    private final FloorServiceInterface floorServiceInterface;

    @Autowired
    @Lazy
    private AccessCardServiceInterface accessCardServiceInterface;

    private final static String IMPORT_CACHE_ROOM_CODE_NAME = "sptg:import:room:code:name";
    private final static String IMPORT_CACHE_ROOM_CODE = "sptg:import:card:room:code";


    @Override
    public ResultBean<Page<Room>> showRoomList(RoomDto roomDto) {
        // 构建查询条件
        Wrapper<Room> wrapper = new EntityWrapper<>();
        //过滤删除
        if (roomDto.getStatus() != null){
            wrapper.eq("i_status", roomDto.getStatus());
        }else {
            wrapper.eq("i_status", OperationConstant.ZERO);
        }
        //根据机构
        if(StringUtils.isNotBlank(roomDto.getOrgPosition())) {
            wrapper.like("s_org_position", roomDto.getOrgPosition(), SqlLike.RIGHT);
        }
        //根据物业
        if(StringUtils.isNotBlank(roomDto.getEstatePosition())) {
            wrapper.like("s_estate_position", roomDto.getEstatePosition(), SqlLike.RIGHT);
        }
        //根据编号查询
        if(StringUtils.isNotBlank(roomDto.getHouseNumber())){
            wrapper.like("s_house_number",roomDto.getHouseNumber());
        }
        //根据名字查询
        if(StringUtils.isNotBlank(roomDto.getName())){
            wrapper.like("s_name",roomDto.getName(),SqlLike.DEFAULT);
        }
        //根据小区ID查询
        if(roomDto.getResidentialId() != null){
            wrapper.eq("l_residential_id",roomDto.getResidentialId());
        }

        //根据楼栋ID查询
        if(roomDto.getBuildingId() != null){
            wrapper.eq("l_building_id",roomDto.getBuildingId());
        }
        //根据单元ID查询
        if(roomDto.getUnitId() != null){
            wrapper.eq("l_unit_id",roomDto.getUnitId());
        }
        //根据楼层ID查询
        if(roomDto.getFloorId() != null){
            wrapper.eq("l_floor_id",roomDto.getFloorId());
        }
        //  排序字段 序号
        if (roomDto.getSortField() != null && roomDto.getSortOrder() != null){
            wrapper.orderBy(roomDto.getSortField(),roomDto.getSortOrder().equals("asc"));
        }else {
            wrapper.orderBy("i_serial");
        }
        wrapper.orderDesc(Arrays.asList("l_unit_id","t_create_date","l_id"));
        return new ResultBean<>(ResultEnum.SUCCESS, this.selectPage(roomDto.getPage(), wrapper));
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public ResultBean<Room> addRoom(RoomDto roomDto) {
        //楼层
        Floor floor = this.floorServiceInterface.findFloorById(roomDto.getFloorId());
        if(null == floor){
            return new ResultBean<>(ResultEnum.NOT_FIND);
        }
        Unit unit = this.unitServiceInterface.findUnitById(floor.getUnitId());
        if(null == unit ){
            return new ResultBean<>(ResultEnum.NOT_FIND);
        }
        Building building = this.buildingServiceInterface.findBuildingById(unit.getBuildingId());
        if(null == building){
            return new ResultBean<>(ResultEnum.NOT_FIND);
        }
        Residential residential = this.residentialServiceInterface.findResidentialById(building.getResidentialId());
        if(null == residential ){
            return new ResultBean<>(ResultEnum.NOT_FIND);
        }
//        if(this.findRoomByCondition(roomDto) > 0 ){
//            return new ResultBean<>(EstateEnum.ROOM_DATA_EXISTES);
//        }
        if (roomDto.getSerial() == null){
            roomDto.setSerial(OperationConstant.ONE);
        }
        roomDto.setResidentialId(residential.getId());
        roomDto.setResidentialName(residential.getName());
        roomDto.setBuildingId(building.getId());
        roomDto.setBuildingName(building.getName());
        roomDto.setUnitId(unit.getId());
        roomDto.setUnitName(unit.getName());
        roomDto.setFloorId(floor.getId());
        roomDto.setFloorName(floor.getName());
        roomDto.setUserNumber(OperationConstant.ZERO);
        roomDto.setRootOrgId(unit.getRootOrgId());
        roomDto.setCreateDate(new Date());
        roomDto.setStatus(OperationConstant.ZERO);

        if(this.insert(roomDto)){
            //小区房间数量加+1
            roomDto.setOrgPosition(floor.getOrgPosition()+roomDto.getId()+"/");
            this.updateById(roomDto);
            residential.setRoomNumber(residential.getRoomNumber() + 1);
            if(this.residentialServiceInterface.updateById(residential)){
                //单元房间数量加+1
                unit.setRoomNumber(unit.getRoomNumber() + 1);
                if(this.unitServiceInterface.updateById(unit)){
                    //楼层房间数量+1
                    floor.setRoomNumber(floor.getRoomNumber() + 1);
                    if (this.floorServiceInterface.updateById(floor)){
                        return new ResultBean<>(ResultEnum.SUCCESS,roomDto);
                    }
                }
            }
        }
        return new ResultBean<>(ResultEnum.ERROR);
    }

    @Override
    public Room findRoomById(Long id) {
        Wrapper<Room> wrapper = new EntityWrapper<>();
        wrapper.eq("l_id",id);
        //过滤删除
        wrapper.notIn("i_status", OperationConstant.MINUS_ONE);
        return this.selectOne(wrapper);
    }

    @Override
    public ResultBean<Boolean> updateRoom(RoomDto roomDto){
        if(this.findRoomByCondition(roomDto) > 0){
            return new ResultBean<>(EstateEnum.ROOM_DATA_EXISTES);
        }
        if(this.updateById(roomDto)){
            return  new ResultBean<>(ResultEnum.SUCCESS,true);
        }
        return new ResultBean<>(ResultEnum.ERROR);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public ResultBean<Boolean> deleteRoom(RoomDto roomDto) {
        Room room = this.findRoomById(roomDto.getId());
        if(null == room ){
            return new ResultBean<>(ResultEnum.ERROR);
        }
        Unit unit = this.unitServiceInterface.findUnitById(room.getUnitId());
        if(null == unit ){
            return new ResultBean<>(ResultEnum.ERROR);
        }
        Residential residential = this.residentialServiceInterface.findResidentialById(unit.getResidentialId());
        if(null == residential ){
            return new ResultBean<>(ResultEnum.ERROR);
        }
        if(room.getUserNumber() > 0){
            return new ResultBean<>(EstateEnum.HAVE_CHILDREN);
        }
        room.setStatus(roomDto.getStatus());
        if(this.updateById(room)){
            //小区房间数量 -1
            residential.setRoomNumber(residential.getRoomNumber()-1);
            if(this.residentialServiceInterface.updateById(residential)){
                //小区房间数量 -1
                unit.setRoomNumber(unit.getRoomNumber() -1);
                if(this.unitServiceInterface.updateById(unit)){
                    //删除关联卡及下发的卡号
                    if(this.accessCardServiceInterface.deleteAccessCardByIdAndType(room.getId(),OperationConstant.ONE)){
                        this.deleteCache(room);
                        return new ResultBean<>(ResultEnum.SUCCESS,true);
                    }
                }
            }
        }
        return new ResultBean<>(ResultEnum.ERROR);
    }

    @Override
    public ResultBean<Boolean> trashOrRecover(RoomDto roomDto) {
        Room room = this.findRoomById(roomDto.getId());
        if(null == room ){
            return new ResultBean<>(ResultEnum.ERROR);
        }
        Unit unit = this.unitServiceInterface.findUnitById(room.getUnitId());
        if(null == unit ){
            return new ResultBean<>(ResultEnum.ERROR);
        }
        Residential residential = this.residentialServiceInterface.findResidentialById(unit.getResidentialId());
        if(null == residential ){
            return new ResultBean<>(ResultEnum.ERROR);
        }
        room.setStatus(roomDto.getStatus());
        if(this.updateById(room)){
            //删除关联卡及下发的卡号
            if(this.accessCardServiceInterface.deleteAccessCardByIdAndType(room.getId(),OperationConstant.ONE)){
                this.deleteCache(room);
                return new ResultBean<>(ResultEnum.SUCCESS,true);
            }
        }
        return new ResultBean<>(ResultEnum.ERROR);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public ResultBean<Boolean> deleteRoomList(RoomDto roomDto) throws Exception {
        List<String> ids = roomDto.getIds();
        String msg;
        for(String id : ids){
            Room room = this.findRoomById(Long.valueOf(id));
            if(null == room ){
                msg = "房间不存在，请核实后重新操作";
                throw new Exception(msg);
            }
            Unit unit = this.unitServiceInterface.findUnitById(room.getUnitId());
            if(null == unit ){
                msg = room.getName() + "房间所属单元不存在，请核实后重新操作";
                throw new Exception(msg);
            }
            Residential residential = this.residentialServiceInterface.findResidentialById(unit.getResidentialId());
            if(null == residential ){
                msg = room.getName() + "房间所属小区不存在，请核实后重新操作";
                throw new Exception(msg);
            }
            if(room.getUserNumber() > 0){
                msg = unit.getName()+"房间含有下级数据，请核实后重新操作";
                throw new Exception(msg);
            }
            room.setStatus(OperationConstant.MINUS_ONE);
            if(this.updateById(room)){
                //小区房间数量 -1
                residential.setRoomNumber(residential.getRoomNumber()-1);
                if(this.residentialServiceInterface.updateById(residential)){
                    //小区房间数量 -1
                    unit.setRoomNumber(unit.getRoomNumber() -1);
                    if(this.unitServiceInterface.updateById(unit)){
                        //删除关联卡及下发的卡号
                        if(this.accessCardServiceInterface.deleteAccessCardByIdAndType(room.getId(),OperationConstant.ONE)){
                            this.deleteCache(room);
                        }else{
                            msg = unit.getName()+"房间删除关联卡失败，请核实后重新操作";
                            throw new Exception(msg);
                        }
                    }
                }
            }
        }
        return new ResultBean<>(ResultEnum.SUCCESS,true);
    }

    @Override
    public ResultBean<Room> findListByPosition(RoomDto roomDto) {
        Wrapper<Room> wrapper = new EntityWrapper<>();
        //过滤删除
        wrapper.notIn("i_status", OperationConstant.MINUS_ONE);
        //根据机构
        if(StringUtils.isNotBlank(roomDto.getOrgPosition())) {
            wrapper.like("s_org_position", roomDto.getOrgPosition(), SqlLike.RIGHT);
        }
        //根据物业
        if(StringUtils.isNotBlank(roomDto.getEstatePosition())) {
            wrapper.like("s_estate_position", roomDto.getEstatePosition(), SqlLike.RIGHT);
        }
        if (roomDto.getResidentialId() != null){
            wrapper.eq("l_residential_id",roomDto.getResidentialId());
        }
        //名称
        if(StringUtils.isNotBlank(roomDto.getName())) {
            wrapper.like("s_name", roomDto.getName(),SqlLike.DEFAULT);
        }
        if (roomDto.getIsSelect()){
            wrapper.last("limit 10");
        }
        return new ResultBean<>(ResultEnum.SUCCESS,this.selectList(wrapper));
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public ResultBean<Boolean> importRoomList(RoomDto roomDto){
        List<Room> list = roomDto.getList();
        if(this.insertBatch(list,500)){
            Map<Long,Integer> residentialMap = roomDto.getResidentialMap();
            for (Map.Entry<Long, Integer> entry : residentialMap.entrySet()) {
                Residential residential = this.residentialServiceInterface.findResidentialById(entry.getKey());
                residential.setRoomNumber(residential.getRoomNumber() + entry.getValue());
                this.residentialServiceInterface.updateById(residential);
            }
            Map<Long,Integer> unitMap = roomDto.getUnitMap();
            for (Map.Entry<Long, Integer> entry : unitMap.entrySet()) {
                Unit unit = this.unitServiceInterface.findUnitById(entry.getKey());
                unit.setRoomNumber(unit.getRoomNumber() + entry.getValue());
                this.unitServiceInterface.updateById(unit);
            }
        }
        return  new ResultBean<>(ExcelResultEnum.SUCCESS,true);
    }

    @Override
    public Room findRoomByNameAndNumber(RoomDto roomDto) {
        Wrapper<Room> wrapper = new EntityWrapper<>();
        //过滤删除
        wrapper.notIn("i_status", OperationConstant.MINUS_ONE);
        wrapper.eq("l_unit_id",roomDto.getUnitId());
        if(StringUtils.isNotBlank(roomDto.getName())){
            //名称
            wrapper.eq("s_name",roomDto.getName());
        }
        if(StringUtils.isNotBlank(roomDto.getHouseNumber())){
            //编号
            wrapper.eq("s_house_number",roomDto.getHouseNumber());
        }
        return this.selectOne(wrapper);
    }

    @Override
    public Room addRoomByImport(Room room) {
        Unit unit = this.unitServiceInterface.findUnitById(room.getUnitId());
        if(null == unit ){
            return null;
        }
        Residential residential = this.residentialServiceInterface.findResidentialById(unit.getResidentialId());
        if(null == residential ){
            return null;
        }
        room.setResidentialId(residential.getId());
        room.setResidentialName(residential.getName());
        room.setUnitName(unit.getName());
        room.setUserNumber(OperationConstant.ZERO);
        room.setRootOrgId(unit.getRootOrgId());
        room.setCreateDate(new Date());
        room.setStatus(OperationConstant.ZERO);
        room.setId(IdWorker.getId());
        room.setOrgPosition(unit.getOrgPosition() + room.getId() + SymbolConstant.BACK_SLASH);
        if(this.insert(room)){
            //小区房间数量加+1
            residential.setRoomNumber(residential.getRoomNumber() + 1);
            if(this.residentialServiceInterface.updateById(residential)){
                //单元房间数量加+1
                unit.setRoomNumber(unit.getRoomNumber() + 1);
                if(this.unitServiceInterface.updateById(unit)){
                    return room;
                }
            }
        }
        return null;
    }

    @Override
    public List<Room> getListByLikeName(RoomDto dto) {
        Wrapper<Room> wrapper = new EntityWrapper<>();
        wrapper.eq("i_status",OperationConstant.ZERO);
        if (dto.getId() != null){
            wrapper.eq("l_id",dto.getId());
        }
        //名称
        if (StringUtils.isNotBlank(dto.getName())){
            wrapper.like("s_name",dto.getName(),SqlLike.DEFAULT);
        }
        if (dto.getResidentialId() != null){
            wrapper.eq("l_residential_id",dto.getResidentialId());
        }
        if (dto.getUnitId() != null){
            wrapper.eq("l_unit_id",dto.getUnitId());
        }
        if (StringUtils.isNotBlank(dto.getOrgPosition())){
            wrapper.like("s_org_position",dto.getOrgPosition(), SqlLike.RIGHT);
        }
        if (StringUtils.isNotBlank(dto.getEstatePosition())){
            wrapper.like("s_estate_position",dto.getEstatePosition(),SqlLike.DEFAULT);
        }
        if (dto.getIsSelect()){
            wrapper.last("limit 10");
        }
        return this.selectList(wrapper);
    }

    @Override
    public Room findByRoomNumber(String roomNumber) {
        Wrapper<Room> wrapper = new EntityWrapper<>();
        //过滤删除
        wrapper.eq("i_status", OperationConstant.ZERO);
        //根据单元id
        wrapper.eq("s_room_number", roomNumber);
        return this.selectOne(wrapper);
    }

    @Override
    public List<Room> getListByCondition(RoomDto roomDto) {
        Wrapper<Room> wrapper = new EntityWrapper<>();
        //过滤删除
        wrapper.eq("i_status", OperationConstant.ZERO);
        //根据orgPosition
        if (StringUtils.isNotBlank(roomDto.getOrgPosition())){
            wrapper.like("s_org_position", roomDto.getOrgPosition());
        }
        //名称
        if (StringUtils.isNotBlank(roomDto.getName())){
            wrapper.like("s_name", roomDto.getName());
        }
        //根据floorId
        if (null != roomDto.getFloorId()){
            wrapper.eq("l_floor_id", roomDto.getFloorId());
        }
        if (null != roomDto.getResidentialId()){
            wrapper.eq("l_residential_id",roomDto.getResidentialId());
        }
        if (null != roomDto.getBuildingId()){
            wrapper.eq("l_building_id",roomDto.getBuildingId());
        }
        if (null != roomDto.getUnitId()){
            wrapper.eq("l_unit_id",roomDto.getUnitId());
        }
        return this.selectList(wrapper);
    }

    @Override
    public Room findByOldId(String oldId) {
        Wrapper<Room> wrapper = new EntityWrapper<>();
        wrapper.eq("i_status",OperationConstant.ZERO);
        wrapper.eq("old_id",oldId);
        return this.selectOne(wrapper);
    }

    @Override
    public int addRoomSync(Room room) {
        if(this.insert(room)){
            return 1;
        }
        return 0;
    }

    @Override
    public int updateRoomSync(Room room) {
        if(this.updateById(room)){
            return 1;
        }
        return 0;
    }

    @Override
    public ResultBean<Room> getByUnitId(Long unitId) {
        Wrapper<Room> wrapper = new EntityWrapper<>();
        //过滤删除
        wrapper.eq("i_status", OperationConstant.ZERO);
        //根据单元id
        wrapper.eq("l_unit_id", unitId);
        return new ResultBean<>(ResultEnum.SUCCESS,this.selectList(wrapper));
    }
    @Override
    public int getRoomAccount(RoomDto roomDto) {
        Wrapper<Room> wrapper = new EntityWrapper<>();
        wrapper.like("s_org_position",roomDto.getOrgPosition(),SqlLike.RIGHT);
        //当月新增
        if(OperationConstant.TWO == roomDto.getIsAllType()){
            wrapper.and("DATE_FORMAT(t_create_date,'%Y%m')=DATE_FORMAT(NOW(),'%Y%m')");
        }
        //过滤删除
        wrapper.notIn("i_status", OperationConstant.MINUS_ONE);
        return this.selectCount(wrapper);
    }

    @Override
    public List<Room> getListByRoomId(List<Long> roomIds) {
        Wrapper<Room> wrapper = new EntityWrapper<>();
        //过滤删除
        wrapper.eq("i_status", OperationConstant.ZERO);
        //用户id
        wrapper.in("l_id", roomIds);
        return this.selectList(wrapper);
    }

    @Override
    public Page<Room> pagingByIds(RoomDto roomDto) {
        Wrapper<Room> wrapper = new EntityWrapper<>();
        //过滤删除
        wrapper.eq("i_status", OperationConstant.ZERO);
        //根据ids
        wrapper.in("l_id",roomDto.getIds());
        return this.selectPage(roomDto.getPage(),wrapper);
    }

    @Override
    public int findRoomByCondition(RoomDto roomDto) {
        Wrapper<Room> wrapper = new EntityWrapper<>();
        //过滤删除
        wrapper.notIn("i_status", OperationConstant.MINUS_ONE);
        //过滤自己
        if(null != roomDto.getId()){
            wrapper.notIn("l_id",roomDto.getId());
        }
        return this.baseMapper.findRoomByCondition(roomDto,wrapper);
    }

    /* -------------------------------------------------- 内部方法 -------------------------------------------------- */
    /* -------------------------------------------------------------------------------------------------------------- */

    /**
     * 功能描述:删除缓存
     * @param room
     *
     *
     */
    private void deleteCache(Room room){
        HashOperations<String, String, String> hashOperations = this.redisTemplate.opsForHash();
        long residentialId = room.getResidentialId();
        long unitId = room.getUnitId();
        String roomName = room.getName();
        String houseNumber = room.getHouseNumber();
        StringBuffer sb = new StringBuffer(residentialId+""+unitId + "-"+roomName+"-"+houseNumber);
        String hashKey = sb.toString();
        String json = hashOperations.get(IMPORT_CACHE_ROOM_CODE_NAME,hashKey);
        if (!StringUtils.isEmpty(json)) {
            hashOperations.delete(IMPORT_CACHE_ROOM_CODE_NAME,hashKey);
        }
        sb = new StringBuffer(unitId+""+houseNumber);
        hashKey = sb.toString();
        json = hashOperations.get(IMPORT_CACHE_ROOM_CODE,hashKey);
        if (!StringUtils.isEmpty(json)) {
            hashOperations.delete(IMPORT_CACHE_ROOM_CODE,hashKey);
        }
    }

    private Room findByHouseNumber(Long unitId, String houseNumber){
        Wrapper<Room> wrapper = new EntityWrapper<>();
        //过滤删除
        wrapper.notIn("i_status", OperationConstant.MINUS_ONE);
        wrapper.eq("l_unit_id", unitId);
        wrapper.eq("s_house_number", houseNumber);
        return this.selectOne(wrapper);
    }

}
